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); ?>