AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.location.gps" />
build.gradle
//통신
implementation 'dev.dworks.libs:volleyplus:+'
implementation "gun0912.ted:tedpermission:2.1.0"
implementation group: 'cz.msebera.android' , name: 'httpclient' , version: '4.4.1.1'
//이미지 crop
implementation 'com.squareup.picasso:picasso:2.3.3'
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".frag.MyFragment">
<!--CardView를 이용해 프로필 사진 이너라인을 적용-->
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="24dp"
app:cardCornerRadius="100dp"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints">
<ImageView
android:id="@+id/my_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_launcher_foreground" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
URLConnector.java
import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class URLConnector extends Thread {
private String result;
private String URL;
public URLConnector(String url){
URL = url;
}
@Override
public void run() {
final String output = request(URL);
result = output;
}
public String getResult(){
return result;
}
private String request(String urlStr) {
StringBuilder output = new StringBuilder();
try {
java.net.URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if (conn != null) {
conn.setConnectTimeout(10000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(true);
int resCode = conn.getResponseCode();
if (resCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())) ;
String line = null;
while(true) {
line = reader.readLine();
if (line == null) {
break;
}
output.append(line + "\n");
}
reader.close();
conn.disconnect();
}
}
} catch(Exception ex) {
Log.e("SampleHTTP", "Exception in processing response.", ex);
ex.printStackTrace();
}
return output.toString();
}
}
FileUploadUtils.java
import android.util.Log;
import java.io.File;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class FileUploadUtils {
public static void send2Server(File file, String email,String partImage) {
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("img", file.getName(), RequestBody.create(MultipartBody.FORM, file))
.addFormDataPart("name",email)
.addFormDataPart("partImage",partImage)
.build();
Request request = new Request.Builder().url("https://서버_아이피/upload.php")
.post(requestBody).build();
OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("TEST : ", response.body().string());
}
});
}
}
DrawUrlImageTask
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
public class DrawUrlImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView ivSample;
public DrawUrlImageTask(ImageView ivSample) {
this.ivSample = ivSample;
}
protected Bitmap doInBackground(String... urls) {
String url = urls[0];
Bitmap bitmap = null;
InputStream in = null;
try {
in = new java.net.URL(url).openStream();
bitmap = BitmapFactory.decodeStream(in);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
protected void onPostExecute(Bitmap bitmap) {
ivSample.setImageBitmap(bitmap);
}
}
MyService.java (Service)
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import androidx.core.app.NotificationCompat;
public abstract class MyService extends Service {
public MyService() {
}
@Override
public void onCreate(){
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startMyOwnForeground();
else
startForeground(1, new Notification());
}
private void startMyOwnForeground(){
String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";
String channelName = "My Background Service";
NotificationChannel chan = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
chan.setLightColor(Color.BLUE);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
}
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
manager.createNotificationChannel(chan);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}
}
CameraFragment.java
ImageView imageView;
//이미지처리 변수 시작
private static final int MY_PERMISSION_CAMERA = 1111;
private static final int REQUEST_TAKE_PHOTO = 2222;
private static final int REQUEST_TAKE_ALBUM = 3333;
private static final int REQUEST_IMAGE_CROP = 4444;
String mCurrentPhotoPath;
File imageFile = null;
Uri imageUri;
Uri photoURI, albumURI;
private static final String TAG = "blackjin";
private Boolean isPermission = true;
public class CameraFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_my, container, false);
mContext = v.getContext();
final String serverURL = "서버_아이피/imagedbSelect.php";
final SharedPreferences sharedPreferences = getActivity().getSharedPreferences("login",getActivity().MODE_PRIVATE);
final SharedPreferences.Editor editor = sharedPreferences.edit();
this.email = sharedPreferences.getString("rememberId","");
this.name = sharedPreferences.getString("rememberName","");
imageView = v.findViewById(R.id.my_img);
Toast.makeText(mContext, "email : "+email, Toast.LENGTH_SHORT).show();
checkPermission();
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(mContext)
.setTitle("이미지 선택")
.setPositiveButton("갤러리", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(isPermission) getAlbum();
else Toast.makeText(mContext, getResources().getString(R.string.permission_2), Toast.LENGTH_LONG).show();
}
})
.setNegativeButton("카메라", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(isPermission) captureCamera();
else Toast.makeText(mContext, getResources().getString(R.string.permission_2), Toast.LENGTH_LONG).show();
}
})
.create().show();
}
});
URLConnector task = new URLConnector(serverURL+"?name="+email+"&partimg="+"ProfileImage");
task.start();
try{
task.join();
System.out.println("waiting... for result");
}
catch(InterruptedException e){
}
//return된 json데이터
String result = task.getResult();
showJson(result);
Log.e("Mycat",result);
return v;
}
//데이터처리
private void showJson(String json){
String TAG_JSON="result";
String TAG_ID = "id";
String TAG_NAME = "name";
String TAG_PARTIMG ="partimg";
String TAG_IMG ="image";
String TAG_DATE ="date";
try {
JSONObject jsonObject = new JSONObject(json);
JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);
for(int i=0;i<jsonArray.length();i++){
JSONObject item = jsonArray.getJSONObject(i);
String id = item.getString(TAG_ID);
String name = item.getString(TAG_NAME);
String partimg = item.getString(TAG_PARTIMG);
String img = item.getString(TAG_IMG);
String date = item.getString(TAG_DATE);
//이미지 url 불러와 이미지 적용
new DrawUrlImageTask((ImageView) imageView)
.execute("서버_주소/"+img);
}
} catch (JSONException e) {
Log.d(TAG, "showResult : ", e);
}
}
//이하 이미지처리
private void captureCamera(){
String state = Environment.getExternalStorageState();
// 외장 메모리 검사
if (Environment.MEDIA_MOUNTED.equals(state)) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
imageFile = null;
try {
imageFile = createImageFile();
} catch (IOException ex) {
Log.e("captureCamera Error", ex.toString());
}
if (imageFile != null) {
// getUriForFile의 두 번째 인자는 Manifest provier의 authorites와 일치해야 함
Uri providerURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName(), imageFile);
imageUri = providerURI;
// 인텐트에 전달할 때는 FileProvier의 Return값인 content://로만!!, providerURI의 값에 카메라 데이터를 넣어 보냄
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, providerURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
} else {
Toast.makeText(mContext, "저장공간이 접근 불가능한 기기입니다", Toast.LENGTH_SHORT).show();
return;
}
}
public File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + ".jpg";
File storageDir = new File(Environment.getExternalStorageDirectory() + "/Pictures", "gyeom");
if (!storageDir.exists()) {
Log.i("mCurrentPhotoPath1", storageDir.toString());
storageDir.mkdirs();
}
imageFile = new File(storageDir, imageFileName);
mCurrentPhotoPath = imageFile.getAbsolutePath();
return imageFile;
}
private void getAlbum(){
Log.i("getAlbum", "Call");
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
intent.setType(android.provider.MediaStore.Images.Media.CONTENT_TYPE);
startActivityForResult(intent, REQUEST_TAKE_ALBUM);
}
private void galleryAddPic(){
Log.i("galleryAddPic", "Call");
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
// 해당 경로에 있는 파일을 객체화(새로 파일을 만든다는 것으로 이해하면 안 됨)
imageFile = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(imageFile);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
Toast.makeText(mContext, "사진이 앨범에 저장되었습니다.", Toast.LENGTH_SHORT).show();
}
// 카메라 전용 크랍
public void cropImage(){
Log.i("cropImage", "Call");
Log.i("cropImage", "photoURI : " + photoURI + " / albumURI : " + albumURI);
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// 50x50픽셀미만은 편집할 수 없다는 문구 처리 + 갤러리, 포토 둘다 호환하는 방법
cropIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
cropIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
cropIntent.setDataAndType(photoURI, "image/*");
//cropIntent.putExtra("outputX", 200); // crop한 이미지의 x축 크기, 결과물의 크기
//cropIntent.putExtra("outputY", 200); // crop한 이미지의 y축 크기
cropIntent.putExtra("aspectX", 1); // crop 박스의 x축 비율, 1&1이면 정사각형
cropIntent.putExtra("aspectY", 1); // crop 박스의 y축 비율
cropIntent.putExtra("scale", true);
cropIntent.putExtra("output", albumURI); // 크랍된 이미지를 해당 경로에 저장
startActivityForResult(cropIntent, REQUEST_IMAGE_CROP);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_TAKE_PHOTO:
if (resultCode == Activity.RESULT_OK) {
try {
Log.i("REQUEST_TAKE_PHOTO", "OK");
galleryAddPic();
imageView.setImageURI(imageUri);
FileUploadUtils.send2Server(imageFile,email,"ProfileImage");
} catch (Exception e) {
Log.e("REQUEST_TAKE_PHOTO", e.toString());
}
} else {
Toast.makeText(mContext, "사진찍기를 취소하였습니다.", Toast.LENGTH_SHORT).show();
}
break;
case REQUEST_TAKE_ALBUM:
if (resultCode == Activity.RESULT_OK) {
if(data.getData() != null){
try {
imageFile = null;
imageFile = createImageFile();
photoURI = data.getData();
albumURI = Uri.fromFile(imageFile);
cropImage();
}catch (Exception e){
Log.e("TAKE_ALBUM_SINGLE ERROR", e.toString());
}
}
}
break;
case REQUEST_IMAGE_CROP:
if (resultCode == Activity.RESULT_OK) {
galleryAddPic();
imageView.setImageURI(albumURI);
FileUploadUtils.send2Server(imageFile,email,"ProfileImage");
}
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSION_CAMERA:
for (int i = 0; i < grantResults.length; i++) {
// grantResults[] : 허용된 권한은 0, 거부한 권한은 -1
if (grantResults[i] < 0) {
Toast.makeText(mContext, "해당 권한을 활성화 하셔야 합니다.", Toast.LENGTH_SHORT).show();
return;
}
}
// 허용했다면 이 부분에서..
break;
}
}
//권한설정
private void checkPermission(){
if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 처음 호출시엔 if()안의 부분은 false로 리턴 됨 -> else{..}의 요청으로 넘어감
if ((ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) ||
(ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.CAMERA))) {
new AlertDialog.Builder(mContext)
.setTitle("알림")
.setMessage("저장소 권한이 거부되었습니다. 사용을 원하시면 설정에서 해당 권한을 직접 허용하셔야 합니다.")
.setNeutralButton("설정", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
startActivity(intent);
}
})
.setPositiveButton("확인", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
getActivity().finish();
}
})
.setCancelable(false)
.create()
.show();
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, MY_PERMISSION_CAMERA);
}
}
}
}
imgDTO.java
public class imgDTO {
String name;
String partimg;
String img;
String date;
public imgDTO(String name, String partimg, String img, String date) {
this.name = name;
this.partimg = partimg;
this.img = img;
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPartimg() {
return partimg;
}
public void setPartimg(String partimg) {
this.partimg = partimg;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
upload.php
<?php
header("Content-Type:text/html; charset=UTF-8");
$name= $_POST['name'];
$partImage= $_POST['partImage'];
$file= $_FILES['img'];
//이미지 파일을 영구보관하기 위해
//이미지 파일의 세부정보 얻어오기
$srcName= $file['name'];
$tmpName= $file['tmp_name']; //php 파일을 받으면 임시저장소에 넣는다. 그곳이 tmp
//임시 저장소 이미지를 원하는 폴더로 이동
$dstName= "uploads/".date('Ymd_his').$srcName;
$result=move_uploaded_file($tmpName, $dstName);
if($result){
echo "upload success\n";
}else{
echo "upload fail\n";
}
echo "$name\n";
echo "$partImage\n";
echo "$dstName\n";
// $name, $partImage, $dstName, $now DB에 저장
// MySQL에 접속
$conn= mysqli_connect("localhost","id","passwd","dbname");
//한글 깨짐 방지
mysqli_query($conn, "set names utf8");
//insert하는 쿼리문
$sql="replace into magedata(name, partimg, image) values('$name','$partImage','$dstName')";
$result =mysqli_query($conn, $sql); //쿼리를 요청하다.
if($result) echo "insert success \n";
else echo "insert fail \n";
mysqli_close($conn);
?>
imagedbSelect.php
<?php
$con=mysqli_connect("localhost","id","passwd","dbname");
if (mysqli_connect_errno($con))
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$PARTIMG = $_GET['partimg'];
$NAME = $_GET['name'];
$result = mysqli_query($con,"SELECT * FROM imagedata where name='$NAME' and partimg='$PARTIMG'");
$data = array();
if ($result) {
while ($row=mysqli_fetch_array($result)) {
array_push($data,array('id'=>$row[0],'name'=>$row[1],'partimg'=>$row[2],'image'=>$row[3],'date'=>$row[4]));
}
header('Content-Type: application/json; charset=utf8');
$json = json_encode(array("result"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
echo $json; // => 출력되는 값이 이 코드로 하여금 android로 전송된다..
} else {
echo "SQL문 처리중 에러 발생 : ";
echo mysqli_error($con);
}
if($data){
echo $data;
}
mysqli_close($con);
?>