├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── kaede │ │ └── howoldrobot │ │ ├── RobotApplication.java │ │ ├── analyse │ │ ├── activity │ │ │ └── MainActivity.java │ │ ├── model │ │ │ ├── Attributes.java │ │ │ ├── Face.java │ │ │ └── FaceRectangle.java │ │ ├── presenter │ │ │ ├── AnalysePresenterCompl.java │ │ │ ├── AnimationPresenterCompl.java │ │ │ ├── DrawPresenterCompl.java │ │ │ ├── IAnalysePresenter.java │ │ │ ├── IAnimationPresenter.java │ │ │ ├── IDrawPresenter.java │ │ │ ├── IOptionsPresenter.java │ │ │ ├── ISharePresenter.java │ │ │ ├── OptionsPresenterCompl.java │ │ │ └── SharePresenterCompl.java │ │ └── view │ │ │ └── IPhotoView.java │ │ ├── util │ │ ├── AppUtil.java │ │ ├── BitmapUtil.java │ │ ├── FileUtil.java │ │ └── NavigationUtil.java │ │ └── widget │ │ ├── AgeIndicatorLayout.java │ │ └── FaceImageView.java │ └── res │ ├── drawable-xhdpi │ ├── bg_button_round.9.png │ └── icon_how_old_02.png │ ├── drawable-xxhdpi │ ├── bg_indicator.9.png │ ├── cardui_round_bg.9.png │ ├── icon_camera.png │ ├── icon_gallery.png │ ├── icon_gende_male.png │ ├── icon_gender_female.png │ ├── icon_launcher.png │ ├── icon_search.png │ └── icon_share.png │ ├── drawable │ └── selector_bg_button_round.xml │ ├── layout │ ├── activity_browser.xml │ ├── activity_main.xml │ ├── fragment_browser.xml │ └── item_age_indicator.xml │ ├── menu │ ├── menu_browser.xml │ └── menu_main.xml │ ├── values-v11 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── color.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /*.iml 10 | /app/*.iml 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | applicationId "me.kaede.howoldrobot" 9 | minSdkVersion 10 10 | targetSdkVersion 22 11 | versionCode 30 12 | versionName "0.3.0" 13 | } 14 | buildTypes { 15 | release { 16 | multiDexEnabled false 17 | minifyEnabled true 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | packagingOptions { 23 | exclude 'META-INF/DEPENDENCIES' 24 | exclude 'META-INF/NOTICE' 25 | exclude 'META-INF/LICENSE' 26 | exclude 'META-INF/LICENSE.txt' 27 | exclude 'META-INF/NOTICE.txt' 28 | } 29 | } 30 | 31 | dependencies { 32 | //compile fileTree(dir: 'libs', include: ['*.jar']) 33 | compile 'com.android.support:appcompat-v7:22.2.1' 34 | compile 'com.android.support:support-v4:22.2.1' 35 | compile 'com.loopj.android:android-async-http:1.4.7' 36 | } 37 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\ADT\android-sdk-as/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/RobotApplication.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Created by kaede on 2015/5/25. 7 | */ 8 | public class RobotApplication extends Application { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.activity; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.os.Bundle; 7 | import android.support.v7.app.ActionBarActivity; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.view.animation.AlphaAnimation; 12 | import android.view.animation.AnimationSet; 13 | import android.view.animation.TranslateAnimation; 14 | import android.widget.Toast; 15 | 16 | import java.util.List; 17 | 18 | import me.kaede.howoldrobot.R; 19 | import me.kaede.howoldrobot.analyse.model.Face; 20 | import me.kaede.howoldrobot.analyse.presenter.AnalysePresenterCompl; 21 | import me.kaede.howoldrobot.analyse.presenter.AnimationPresenterCompl; 22 | import me.kaede.howoldrobot.analyse.presenter.DrawPresenterCompl; 23 | import me.kaede.howoldrobot.analyse.presenter.IAnalysePresenter; 24 | import me.kaede.howoldrobot.analyse.presenter.IAnimationPresenter; 25 | import me.kaede.howoldrobot.analyse.presenter.IDrawPresenter; 26 | import me.kaede.howoldrobot.analyse.presenter.IOptionsPresenter; 27 | import me.kaede.howoldrobot.analyse.presenter.ISharePresenter; 28 | import me.kaede.howoldrobot.analyse.presenter.OptionsPresenterCompl; 29 | import me.kaede.howoldrobot.analyse.presenter.SharePresenterCompl; 30 | import me.kaede.howoldrobot.analyse.view.IPhotoView; 31 | import me.kaede.howoldrobot.widget.AgeIndicatorLayout; 32 | import me.kaede.howoldrobot.widget.FaceImageView; 33 | 34 | 35 | public class MainActivity extends ActionBarActivity implements IPhotoView, View.OnClickListener { 36 | 37 | public static final int ACTIVITY_REQUEST_CAMERA = 0; 38 | public static final int ACTIVITY_REQUEST_GALLERY = 1; 39 | private IAnalysePresenter analysePresenter; 40 | private IDrawPresenter drawPresenter; 41 | private FaceImageView faceImageView; 42 | private ProgressDialog progressDialog; 43 | private AgeIndicatorLayout ageIndicatorLayout; 44 | private View photoContainer; 45 | 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_main); 51 | injectView(); 52 | setListener(); 53 | init(); 54 | } 55 | 56 | private void injectView(){ 57 | faceImageView = (FaceImageView) this.findViewById(R.id.iv_main_face); 58 | ageIndicatorLayout = (AgeIndicatorLayout) this.findViewById(R.id.layout_main_age); 59 | photoContainer = this.findViewById(R.id.layout_main_photo); 60 | } 61 | 62 | private void setListener() { 63 | this.findViewById(R.id.btn_main_camera).setOnClickListener(this); 64 | this.findViewById(R.id.btn_main_gallery).setOnClickListener(this); 65 | this.findViewById(R.id.btn_main_share).setOnClickListener(this); 66 | } 67 | 68 | private void init() { 69 | analysePresenter = new AnalysePresenterCompl(this); 70 | drawPresenter = new DrawPresenterCompl(this, this); 71 | try { 72 | getSupportActionBar().setElevation(0);//取消Actionbar阴影(5.0后生效) 73 | getSupportActionBar().setTitle(getResources().getString(R.string.app_name)); 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | } 77 | IAnimationPresenter animationPresenter = new AnimationPresenterCompl(); 78 | animationPresenter.doLogoAnimation(findViewById(R.id.iv_main_introduce_logo)); 79 | animationPresenter.doIntroduceAnimation(findViewById(R.id.layout_main_introduce_text)); 80 | } 81 | 82 | @Override 83 | public void onGetFaces(List faces) { 84 | showProgressDialog(false); 85 | if (faces==null){ 86 | toast(getResources().getString(R.string.main_analyze_fail)); 87 | }else if (faces.size()<=0){ 88 | toast(getResources().getString(R.string.main_analyze_no_face)); 89 | }else { 90 | drawPresenter.drawFaces(ageIndicatorLayout, faceImageView, faces); 91 | } 92 | } 93 | 94 | @Override 95 | public void onGetImage(Bitmap bitmap, String imgPath) { 96 | faceImageView.clearFaces(); 97 | ageIndicatorLayout.clearAges(); 98 | faceImageView.setImageBitmap(bitmap); 99 | this.findViewById(R.id.layout_main_introduce).setVisibility(View.GONE); 100 | this.findViewById(R.id.layout_main_border).setBackgroundResource(R.color.orange_500); 101 | analysePresenter.doAnalyse(imgPath); 102 | } 103 | 104 | @Override 105 | public void showProgressDialog(Boolean isShow) { 106 | if (progressDialog == null){ 107 | progressDialog = new ProgressDialog(this); 108 | progressDialog.setIndeterminate(true); 109 | progressDialog.setCancelable(false); 110 | progressDialog.setCanceledOnTouchOutside(false); 111 | progressDialog.setMessage(getResources().getString(R.string.main_loading)); 112 | } 113 | if (isShow){ 114 | if (!progressDialog.isShowing()) 115 | progressDialog.show(); 116 | }else { 117 | if (progressDialog.isShowing()) 118 | progressDialog.dismiss(); 119 | } 120 | 121 | 122 | } 123 | 124 | @Override 125 | public void toast(String msg) { 126 | Toast.makeText(this,msg,Toast.LENGTH_LONG).show(); 127 | } 128 | 129 | @Override 130 | public View getPhotoContainer() { 131 | return photoContainer; 132 | } 133 | 134 | @Override 135 | public boolean onCreateOptionsMenu(Menu menu) { 136 | getMenuInflater().inflate(R.menu.menu_main, menu); 137 | return super.onCreateOptionsMenu(menu); 138 | } 139 | 140 | @Override 141 | public boolean onOptionsItemSelected(MenuItem item) { 142 | IOptionsPresenter optionsPresenter = new OptionsPresenterCompl(); 143 | optionsPresenter.onOptionsItemClick(this,item.getItemId()); 144 | return super.onOptionsItemSelected(item); 145 | } 146 | 147 | @Override 148 | public void onClick(View v) { 149 | 150 | switch(v.getId()) { 151 | case R.id.btn_main_camera: 152 | analysePresenter.pickPhoto(this,AnalysePresenterCompl.TYPE_PICK_CAMERA); 153 | break; 154 | case R.id.btn_main_gallery: 155 | analysePresenter.pickPhoto(this,AnalysePresenterCompl.TYPE_PICK_GALLERY); 156 | break; 157 | case R.id.btn_main_share: 158 | ISharePresenter sharePresenter = new SharePresenterCompl(this); 159 | sharePresenter.doShare(this, this.findViewById(android.R.id.content)); 160 | break; 161 | default: 162 | break; 163 | } 164 | } 165 | 166 | @Override 167 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 168 | super.onActivityResult(requestCode, resultCode, data); 169 | switch(requestCode){ 170 | case ACTIVITY_REQUEST_CAMERA: 171 | case ACTIVITY_REQUEST_GALLERY: 172 | if(resultCode==RESULT_OK){ 173 | analysePresenter.getImage(this,data); 174 | } 175 | break; 176 | default: 177 | break; 178 | } 179 | } 180 | 181 | 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/model/Attributes.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.model; 2 | 3 | public class Attributes{ 4 | @Override 5 | public String toString() { 6 | return "Attributes{" + 7 | "gender='" + gender + '\'' + 8 | ", age=" + age + 9 | '}'; 10 | } 11 | 12 | public String gender; 13 | public int age; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/model/Face.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.model; 2 | 3 | /** 4 | * Created by kaede on 2015/5/23. 5 | */ 6 | public class Face { 7 | public int faceId; 8 | public FaceRectangle faceRectangle; 9 | public Attributes attributes; 10 | public Face(){ 11 | faceRectangle = new FaceRectangle(); 12 | attributes = new Attributes(); 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "Face{" + 18 | "faceId=" + faceId + 19 | ", faceRectangle=" + faceRectangle + 20 | ", attributes=" + attributes + 21 | '}'; 22 | } 23 | } 24 | 25 | 26 | 27 | /* 28 | [ 29 | { 30 | "faceId": null, 31 | "faceRectangle": { 32 | "top": 181, 33 | "left": 568, 34 | "width": 37, 35 | "height": 37 36 | }, 37 | "attributes": { 38 | "gender": "Female", 39 | "age": 25 40 | } 41 | }, 42 | { 43 | "faceId": null, 44 | "faceRectangle": { 45 | "top": 184, 46 | "left": 490, 47 | "width": 35, 48 | "height": 35 49 | }, 50 | "attributes": { 51 | "gender": "Male", 52 | "age": 26 53 | } 54 | }, 55 | { 56 | "faceId": null, 57 | "faceRectangle": { 58 | "top": 159, 59 | "left": 326, 60 | "width": 35, 61 | "height": 35 62 | }, 63 | "attributes": { 64 | "gender": "Male", 65 | "age": 44.5 66 | } 67 | }, 68 | { 69 | "faceId": null, 70 | "faceRectangle": { 71 | "top": 184, 72 | "left": 635, 73 | "width": 33, 74 | "height": 33 75 | }, 76 | "attributes": { 77 | "gender": "Male", 78 | "age": 20.5 79 | } 80 | }, 81 | { 82 | "faceId": null, 83 | "faceRectangle": { 84 | "top": 184, 85 | "left": 254, 86 | "width": 33, 87 | "height": 33 88 | }, 89 | "attributes": { 90 | "gender": "Female", 91 | "age": 24 92 | } 93 | }, 94 | { 95 | "faceId": null, 96 | "faceRectangle": { 97 | "top": 187, 98 | "left": 158, 99 | "width": 32, 100 | "height": 32 101 | }, 102 | "attributes": { 103 | "gender": "Female", 104 | "age": 25 105 | } 106 | }, 107 | { 108 | "faceId": null, 109 | "faceRectangle": { 110 | "top": 187, 111 | "left": 400, 112 | "width": 31, 113 | "height": 31 114 | }, 115 | "attributes": { 116 | "gender": "Female", 117 | "age": 24 118 | } 119 | } 120 | ] 121 | */ 122 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/model/FaceRectangle.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.model; 2 | 3 | public class FaceRectangle{ 4 | public int left; 5 | public int top; 6 | public int width; 7 | public int height; 8 | 9 | @Override 10 | public String toString() { 11 | return "FaceRectangle{" + 12 | "left=" + left + 13 | ", top=" + top + 14 | ", width=" + width + 15 | ", height=" + height + 16 | '}'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/AnalysePresenterCompl.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.net.Uri; 9 | import android.provider.MediaStore; 10 | import android.util.Log; 11 | 12 | import com.loopj.android.http.AsyncHttpClient; 13 | import com.loopj.android.http.AsyncHttpResponseHandler; 14 | import com.loopj.android.http.RequestParams; 15 | 16 | import org.apache.http.Header; 17 | import org.json.JSONArray; 18 | import org.json.JSONObject; 19 | 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.UnsupportedEncodingException; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import me.kaede.howoldrobot.R; 27 | import me.kaede.howoldrobot.analyse.activity.MainActivity; 28 | import me.kaede.howoldrobot.analyse.model.Face; 29 | import me.kaede.howoldrobot.analyse.view.IPhotoView; 30 | import me.kaede.howoldrobot.util.AppUtil; 31 | import me.kaede.howoldrobot.util.BitmapUtil; 32 | import me.kaede.howoldrobot.util.FileUtil; 33 | 34 | /** 35 | * Created by kaede on 2015/5/23. 36 | */ 37 | public class AnalysePresenterCompl implements IAnalysePresenter { 38 | private static final String TAG = "AnalysePresenterCompl"; 39 | public static final int TYPE_PICK_CAMERA = 0; 40 | public static final int TYPE_PICK_GALLERY = 1; 41 | private static final String OUTPUT_IMAGE_JPG = "output_image.jpg"; 42 | private static final String OUTPUT_IMAGE_SMALL_JPG = "output_image_small.jpg"; 43 | IPhotoView iPhotoView; 44 | File appBaseDir; 45 | private Uri imageUri; 46 | private AsyncHttpClient asyncHttpClient; 47 | 48 | public AnalysePresenterCompl(IPhotoView iPhotoView) { 49 | this.iPhotoView = iPhotoView; 50 | File dir = new File(FileUtil.getSdpath() + File.separator + "Moe Studio"); 51 | dir.mkdir(); 52 | appBaseDir = new File(dir.getAbsolutePath() + File.separator + "How Old Robot"); 53 | appBaseDir.mkdir(); 54 | } 55 | 56 | @Override 57 | public void doAnalyse(String imgPath) { 58 | File file = new File(imgPath); 59 | if (!file.exists()) { 60 | Log.w(TAG, "Image Not Exists!"); 61 | return; 62 | } 63 | postRequest(imgPath); 64 | 65 | } 66 | 67 | @Override 68 | public void pickPhoto(Activity activity, int type) { 69 | File outputImage; 70 | switch (type) { 71 | case TYPE_PICK_CAMERA: 72 | Intent takePicture = new Intent("android.media.action.IMAGE_CAPTURE"); 73 | outputImage = new File(appBaseDir.getAbsolutePath() + File.separator + OUTPUT_IMAGE_JPG); 74 | if (!outputImage.exists()) try { 75 | outputImage.createNewFile(); 76 | } catch (IOException e) { 77 | e.printStackTrace(); 78 | } 79 | imageUri = Uri.fromFile(outputImage); 80 | //takePicture.putExtra("return-data", false); 81 | takePicture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 82 | try { 83 | activity.startActivityForResult(takePicture, MainActivity.ACTIVITY_REQUEST_CAMERA); 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | iPhotoView.toast(activity.getResources().getString(R.string.main_pick_camera_fail)); 87 | } 88 | break; 89 | case TYPE_PICK_GALLERY: 90 | Intent pickPhoto = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 91 | pickPhoto.putExtra("crop", "true");//允许裁剪 92 | outputImage = new File(appBaseDir.getAbsolutePath() + File.separator + OUTPUT_IMAGE_JPG); 93 | if (!outputImage.exists()) try { 94 | outputImage.createNewFile(); 95 | } catch (IOException e) { 96 | e.printStackTrace(); 97 | } 98 | imageUri = Uri.fromFile(outputImage); 99 | //takePicture.putExtra("return-data", false); 100 | pickPhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 101 | try { 102 | activity.startActivityForResult(pickPhoto, MainActivity.ACTIVITY_REQUEST_GALLERY); 103 | } catch (Exception e) { 104 | e.printStackTrace(); 105 | pickPhoto.putExtra("crop", false);//不允许裁剪 106 | try { 107 | activity.startActivityForResult(pickPhoto, MainActivity.ACTIVITY_REQUEST_GALLERY); 108 | } catch (Throwable t) { 109 | t.printStackTrace(); 110 | iPhotoView.toast(activity.getResources().getString(R.string.main_pick_gallery_fail)); 111 | } 112 | } 113 | break; 114 | default: 115 | break; 116 | } 117 | } 118 | 119 | @Override 120 | public void getImage(Context context, Intent intent) { 121 | try { 122 | Bitmap bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imageUri)); 123 | //为防止原始图片过大导致内存溢出,这里先缩小原图显示,然后释放原始Bitmap占用的内存 124 | int widthBitmap = bitmap.getWidth(); 125 | int heightBitmap = bitmap.getHeight(); 126 | int widthMax = AppUtil.getScreenWitdh(context) - (context.getResources().getDimensionPixelSize(R.dimen.margin_main_left) + context.getResources().getDimensionPixelSize(R.dimen.border_main_photo) + context.getResources().getDimensionPixelSize(R.dimen.offset_main_photo)) * 2; 127 | int heightMax = iPhotoView.getPhotoContainer().getHeight() - (context.getResources().getDimensionPixelSize(R.dimen.border_main_photo) + context.getResources().getDimensionPixelSize(R.dimen.offset_main_photo)) * 2; 128 | if (widthBitmap > widthMax && heightBitmap > heightMax) { 129 | float rateWidth = (float)widthBitmap/(float)widthMax; 130 | float rateHeight = (float)heightBitmap/(float)heightMax; 131 | if (rateWidth>=rateHeight) 132 | bitmap = BitmapUtil.zoomBitmapToWidth(bitmap, widthMax); 133 | else 134 | bitmap = BitmapUtil.zoomBitmapToHeight(bitmap, heightMax); 135 | }else if (widthBitmap > widthMax){ 136 | bitmap = BitmapUtil.zoomBitmapToWidth(bitmap, widthMax); 137 | }else if(heightBitmap>heightMax){ 138 | bitmap = BitmapUtil.zoomBitmapToHeight(bitmap, heightMax); 139 | } 140 | String imgPath = appBaseDir.getAbsolutePath() + File.separator + OUTPUT_IMAGE_SMALL_JPG; 141 | if (BitmapUtil.saveBitmapToSd(bitmap,80,imgPath)) 142 | iPhotoView.onGetImage(bitmap, imgPath); 143 | } catch (Exception e) { 144 | iPhotoView.toast(context.getResources().getString(R.string.main_get_img_fail)); 145 | e.printStackTrace(); 146 | } 147 | } 148 | 149 | private void postRequest(String imagePath) { 150 | iPhotoView.showProgressDialog(true); 151 | try { 152 | if (asyncHttpClient==null)asyncHttpClient = new AsyncHttpClient(); 153 | RequestParams params = new RequestParams(); 154 | params.put("data", new File(imagePath)); // Upload a File 155 | //params.put("data", new Base64InputStream(new FileInputStream(imagePath),Base64.DEFAULT)); // Upload a File 156 | params.put("isTest", "False"); 157 | Log.d(TAG, "do post "); 158 | asyncHttpClient.post("http://how-old.net/Home/Analyze?isTest=False", params, new AsyncHttpResponseHandler() { 159 | @Override 160 | public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { 161 | Log.d(TAG, "onSuccess: statusCode = " + statusCode); 162 | try { 163 | String string = new String(responseBody, "UTF-8"); 164 | String str1 = string.replaceAll("\\\\", ""); 165 | String str2 = str1.replaceAll("rn", ""); 166 | String json = str2.substring(str2.indexOf("\"Faces\":[") + 8, str2.lastIndexOf("]") + 1); 167 | Log.d(TAG, "onSuccess: json = " + json); 168 | parserJson(json); 169 | } catch (UnsupportedEncodingException e) { 170 | e.printStackTrace(); 171 | } 172 | } 173 | 174 | @Override 175 | public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { 176 | Log.d(TAG, "onFailure: statusCode = " + statusCode); 177 | parserJson(null); 178 | } 179 | }); 180 | 181 | } catch (Exception e) { 182 | e.printStackTrace(); 183 | parserJson(null); 184 | } 185 | 186 | //new PostHandler().execute(imagePath); 187 | } 188 | 189 | private void parserJson(String string) { 190 | if (string == null) { 191 | iPhotoView.onGetFaces(null); 192 | return; 193 | } 194 | List faceList = new ArrayList<>(); 195 | try { 196 | JSONArray jsonArray = new JSONArray(string); 197 | if (jsonArray.length() <= 0) { 198 | Log.w(TAG, "No Face"); 199 | } 200 | for (int i = 0; i < jsonArray.length(); i++) { 201 | JSONObject item = jsonArray.getJSONObject(i); 202 | Face face = new Face(); 203 | face.faceId = item.optInt("faceId", 0); 204 | JSONObject faceRectangle = item.optJSONObject("faceRectangle"); 205 | face.faceRectangle.left = faceRectangle.optInt("left", 0); 206 | face.faceRectangle.top = faceRectangle.optInt("top", 0); 207 | face.faceRectangle.width = faceRectangle.optInt("width", 65); 208 | face.faceRectangle.height = faceRectangle.optInt("height", 65); 209 | JSONObject attributes = item.optJSONObject("attributes"); 210 | face.attributes.gender = attributes.optString("gender", "Female"); 211 | face.attributes.age = attributes.optInt("age", 17); 212 | faceList.add(face); 213 | } 214 | } catch (Exception e) { 215 | e.printStackTrace(); 216 | } 217 | 218 | /*Iterator iterator = faceList.iterator(); 219 | while (iterator.hasNext()) { 220 | Face item = iterator.next(); 221 | Log.d(TAG, "Face : " + item.toString()); 222 | }*/ 223 | iPhotoView.onGetFaces(faceList); 224 | } 225 | 226 | 227 | 228 | /*class PostHandler extends AsyncTask { 229 | 230 | 231 | @Override 232 | protected String doInBackground(String... params) { 233 | try { 234 | HttpClient httpclient = new DefaultHttpClient(); 235 | HttpPost httppost = new HttpPost("http://how-old.net/Home/Analyze?isTest=False"); 236 | // 一个本地的文件 237 | FileBody file = new FileBody(new File(params[0])); 238 | // 一个字符串 239 | StringBody comment = new StringBody("False"); 240 | // 多部分的实体 241 | MultipartEntity reqEntity = new MultipartEntity(); 242 | // 增加 243 | reqEntity.addPart("data", file); 244 | reqEntity.addPart("isTest", comment); 245 | // 设置 246 | httppost.setEntity(reqEntity); 247 | 248 | Log.d(TAG, "执行: " + httppost.getRequestLine()); 249 | 250 | HttpResponse response = httpclient.execute(httppost); 251 | HttpEntity resEntity = response.getEntity(); 252 | Header[] headers = response.getAllHeaders(); 253 | for (Header header : headers) { 254 | System.out.println(header.getName() + " " + header.getValue()); 255 | } 256 | System.out.println("----------------------------------------"); 257 | System.out.println(response.getStatusLine()); 258 | if (resEntity != null) { 259 | Log.d(TAG, "返回长度: " + resEntity.getContentLength()); 260 | String result = EntityUtils.toString(resEntity, "utf-8"); 261 | String str1 = result.replaceAll("\\\\", ""); 262 | String str2 = str1.replaceAll("rn", ""); 263 | String json = str2.substring(str2.indexOf("\"Faces\":[") + 8, str2.lastIndexOf("]") + 1); 264 | resEntity.consumeContent(); 265 | Log.d(TAG, json); 266 | return json; 267 | } 268 | } catch (Exception e) { 269 | e.printStackTrace(); 270 | } 271 | return null; 272 | 273 | } 274 | 275 | @Override 276 | protected void onPreExecute() { 277 | super.onPreExecute(); 278 | iPhotoView.showProgressDialog(true); 279 | } 280 | 281 | @Override 282 | protected void onPostExecute(String s) { 283 | super.onPostExecute(s); 284 | parserJson(s); 285 | } 286 | }*/ 287 | } 288 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/AnimationPresenterCompl.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.view.View; 4 | import android.view.animation.AlphaAnimation; 5 | import android.view.animation.AnimationSet; 6 | import android.view.animation.TranslateAnimation; 7 | 8 | /** 9 | * Created by Kaede on 2015/6/2. 10 | */ 11 | public class AnimationPresenterCompl implements IAnimationPresenter { 12 | @Override 13 | public void doLogoAnimation(View view) { 14 | AnimationSet animationSet = new AnimationSet(false); 15 | AlphaAnimation alphaAnimation = new AlphaAnimation(0,1); 16 | alphaAnimation.setDuration(1000); 17 | alphaAnimation.setFillAfter(true); 18 | TranslateAnimation translateAnimation = new TranslateAnimation(0f,0f,100f,0f); 19 | translateAnimation.setDuration(1000); 20 | translateAnimation.setFillAfter(true); 21 | animationSet.addAnimation(alphaAnimation); 22 | animationSet.addAnimation(translateAnimation); 23 | view.startAnimation(animationSet); 24 | } 25 | 26 | @Override 27 | public void doIntroduceAnimation(View view) { 28 | AlphaAnimation alphaAnimation = new AlphaAnimation(0,1); 29 | alphaAnimation.setDuration(500); 30 | alphaAnimation.setStartOffset(500); 31 | alphaAnimation.setFillAfter(true); 32 | view.startAnimation(alphaAnimation); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/DrawPresenterCompl.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.app.Activity; 4 | import android.view.View; 5 | 6 | import me.kaede.howoldrobot.analyse.model.Face; 7 | import me.kaede.howoldrobot.analyse.view.IPhotoView; 8 | import me.kaede.howoldrobot.widget.FaceImageView; 9 | import me.kaede.howoldrobot.widget.AgeIndicatorLayout; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by kaede on 2015/5/24. 16 | */ 17 | public class DrawPresenterCompl implements IDrawPresenter { 18 | Listviews; 19 | IPhotoView iPhotoView; 20 | /*private WindowManager windowManager; 21 | private WindowManager.LayoutParams params;*/ 22 | 23 | public DrawPresenterCompl(Activity activity,IPhotoView iPhotoView) { 24 | this.iPhotoView = iPhotoView; 25 | views = new ArrayList<>(); 26 | 27 | /*windowManager = activity.getWindowManager(); 28 | params = new WindowManager.LayoutParams( 29 | WindowManager.LayoutParams.WRAP_CONTENT, 30 | WindowManager.LayoutParams.WRAP_CONTENT, 31 | WindowManager.LayoutParams.LAST_APPLICATION_WINDOW, 32 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 33 | PixelFormat.TRANSLUCENT); 34 | params.gravity = Gravity.TOP | Gravity.START;*/ 35 | 36 | } 37 | 38 | 39 | @Override 40 | public void drawFaces(AgeIndicatorLayout ageIndicatorLayout, FaceImageView faceImageView, List faces) { 41 | faceImageView.drawFaces(faces); 42 | ageIndicatorLayout.drawAges(faces, (ageIndicatorLayout.getMeasuredWidth()-faceImageView.getMeasuredWidth())/2, (ageIndicatorLayout.getMeasuredHeight()-faceImageView.getMeasuredHeight())/2); 43 | 44 | 45 | //使用WindowManager显示AgeIndicator 46 | /*View photoContainer = activity.findViewById(R.id.layout_main_photo); 47 | *//* 获取状态栏高度 48 | Rect frame = new Rect(); 49 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 50 | int statusBarHeight = frame.top;*//* 51 | int x_center = photoContainer.getMeasuredWidth()/2; 52 | int y_center = photoContainer.getMeasuredHeight()/2; 53 | int x = x_center - faceImageView.getMeasuredWidth()/2 + activity.getResources().getDimensionPixelSize(R.dimen.margin_main_left); 54 | int y = y_center - faceImageView.getMeasuredHeight()/2+ activity.getResources().getDimensionPixelSize(R.dimen.margin_main_top) + activity.getResources().getDimensionPixelSize(R.dimen.common_actionbar_height); 55 | 56 | 57 | Iterator iterator = faces.iterator(); 58 | while (iterator.hasNext()){ 59 | Face item = iterator.next(); 60 | params.x = x+item.faceRectangle.left - (activity.getResources().getDimensionPixelSize(R.dimen.indicator_width) - item.faceRectangle.width)/2; 61 | params.y = y+item.faceRectangle.top - activity.getResources().getDimensionPixelSize(R.dimen.indicator_height); 62 | View ageIndicateView = LayoutInflater.from(activity.getApplicationContext()).inflate( 63 | R.layout.item_age_indicator, null); 64 | if (ageIndicateView!=null){ 65 | TextView tvAge = (TextView) ageIndicateView.findViewById(R.id.tv_ageindicator_age); 66 | tvAge.setText(String.valueOf(item.attributes.age)); 67 | ImageView ivGender = (ImageView) ageIndicateView.findViewById(R.id.iv_ageindicator_gender); 68 | if (item.attributes.gender.equalsIgnoreCase("Male")){ 69 | ivGender.setImageResource(R.drawable.icon_gende_male); 70 | }else if(item.attributes.gender.equalsIgnoreCase("Female")){ 71 | ivGender.setImageResource(R.drawable.icon_gender_female); 72 | } 73 | views.add(ageIndicateView); 74 | windowManager.addView(ageIndicateView, params); 75 | } 76 | }*/ 77 | } 78 | 79 | @Override 80 | public void clearViews() { 81 | /*Iterator iterator = views.iterator(); 82 | while (iterator.hasNext()){ 83 | View view = iterator.next(); 84 | windowManager.removeViewImmediate(view); 85 | } 86 | views.clear();*/ 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/IAnalysePresenter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | /** 8 | * Created by kaede on 2015/5/23. 9 | */ 10 | public interface IAnalysePresenter { 11 | public void doAnalyse(String imgPath); 12 | public void pickPhoto(Activity activity,int type); 13 | public void getImage(Context context,Intent intent); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/IAnimationPresenter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by Kaede on 2015/6/2. 7 | */ 8 | public interface IAnimationPresenter { 9 | 10 | public void doLogoAnimation(View view); 11 | public void doIntroduceAnimation(View view); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/IDrawPresenter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import java.util.List; 4 | 5 | import me.kaede.howoldrobot.analyse.model.Face; 6 | import me.kaede.howoldrobot.widget.AgeIndicatorLayout; 7 | import me.kaede.howoldrobot.widget.FaceImageView; 8 | 9 | /** 10 | * Created by kaede on 2015/5/24. 11 | */ 12 | public interface IDrawPresenter { 13 | public void drawFaces(AgeIndicatorLayout ageIndicatorLayout, FaceImageView faceImageView,List faces); 14 | public void clearViews(); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/IOptionsPresenter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by kaede on 2015/5/26. 7 | */ 8 | public interface IOptionsPresenter { 9 | public void onOptionsItemClick(Context context,int id); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/ISharePresenter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by kaede on 2015/5/25. 8 | */ 9 | public interface ISharePresenter { 10 | public void doShare(Context context, View view); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/OptionsPresenterCompl.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | 7 | import me.kaede.howoldrobot.R; 8 | import me.kaede.howoldrobot.util.AppUtil; 9 | import me.kaede.howoldrobot.util.NavigationUtil; 10 | 11 | /** 12 | * Created by kaede on 2015/5/26. 13 | */ 14 | public class OptionsPresenterCompl implements IOptionsPresenter { 15 | @Override 16 | public void onOptionsItemClick(Context context, int id) { 17 | switch(id) { 18 | case R.id.action_star: 19 | NavigationUtil.naviToMarket(context, AppUtil.getpackageName(context)); 20 | break; 21 | case R.id.action_web: 22 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://how-old.net")); 23 | context.startActivity(browserIntent); 24 | //NavigationUtil.toWebViewActivity(context,"http://how-old.net/","Online"); 25 | break; 26 | default: 27 | break; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/presenter/SharePresenterCompl.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.presenter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.net.Uri; 7 | import android.provider.MediaStore; 8 | import android.view.View; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | 13 | import me.kaede.howoldrobot.R; 14 | import me.kaede.howoldrobot.analyse.view.IPhotoView; 15 | import me.kaede.howoldrobot.util.BitmapUtil; 16 | import me.kaede.howoldrobot.util.FileUtil; 17 | 18 | /** 19 | * Created by kaede on 2015/5/25. 20 | */ 21 | public class SharePresenterCompl implements ISharePresenter { 22 | IPhotoView iPhotoView; 23 | File appBaseDir; 24 | 25 | public SharePresenterCompl(IPhotoView iPhotoView) { 26 | this.iPhotoView = iPhotoView; 27 | File dir = new File(FileUtil.getSdpath() + File.separator + "Moe Studio"); 28 | dir.mkdir(); 29 | appBaseDir = new File(dir.getAbsolutePath() + File.separator + "How Old Robot"); 30 | appBaseDir.mkdir(); 31 | } 32 | 33 | @Override 34 | public void doShare(Context context, View view) { 35 | Bitmap b = BitmapUtil.getViewBitmap(view); 36 | if (b!=null){ 37 | File temp = FileUtil.getTempFile(appBaseDir.getAbsolutePath(),".jpg"); 38 | if (temp != null) { 39 | BitmapUtil.saveBitmapToSd(b,80,temp.getAbsolutePath()); 40 | } 41 | Intent share = new Intent(Intent.ACTION_SEND); 42 | share.setType("image/jpeg"); 43 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 44 | b.compress(Bitmap.CompressFormat.JPEG, 80, bytes); 45 | String path = MediaStore.Images.Media.insertImage(context.getContentResolver(),b, "Share Image", "How Old Camera's Share Image"); 46 | Uri imageUri = Uri.parse(path); 47 | share.putExtra(Intent.EXTRA_STREAM, imageUri); 48 | try { 49 | context.startActivity(Intent.createChooser(share, context.getResources().getString(R.string.share_select_title))); 50 | } catch (Exception e) { 51 | iPhotoView.toast(context.getResources().getString(R.string.share_fail)); 52 | e.printStackTrace(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/analyse/view/IPhotoView.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.analyse.view; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import java.util.List; 6 | 7 | import android.view.View; 8 | import me.kaede.howoldrobot.analyse.model.Face; 9 | 10 | /** 11 | * Created by kaede on 2015/5/23. 12 | */ 13 | public interface IPhotoView { 14 | public void onGetFaces(List faces); 15 | public void onGetImage(Bitmap bitmap,String imgPath); 16 | public void showProgressDialog(Boolean isShow); 17 | public void toast(String msg); 18 | public View getPhotoContainer(); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/util/AppUtil.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.util; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.util.DisplayMetrics; 7 | 8 | /** 9 | * Created by kaede on 2015/5/24. 10 | */ 11 | public class AppUtil { 12 | public static int getScreenWitdh(Context context){ 13 | DisplayMetrics dm = new DisplayMetrics(); 14 | dm = context.getResources().getDisplayMetrics(); 15 | return dm.widthPixels; 16 | } 17 | 18 | public static int getScreenHeight(Context context){ 19 | DisplayMetrics dm = new DisplayMetrics(); 20 | dm = context.getResources().getDisplayMetrics(); 21 | return dm.heightPixels; 22 | } 23 | 24 | public static String getpackageName(Context context) { 25 | // 获取packagemanager的实例 26 | PackageManager packageManager = context.getPackageManager(); 27 | // getPackageName()是你当前类的包名,0代表是获取版本信息 28 | PackageInfo packInfo = null; 29 | try { 30 | packInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 31 | } catch (PackageManager.NameNotFoundException e) { 32 | e.printStackTrace(); 33 | } 34 | String pack = packInfo.packageName; 35 | return pack; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/util/BitmapUtil.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.*; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.DisplayMetrics; 7 | import android.util.Log; 8 | import android.view.Display; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | 12 | import java.io.*; 13 | 14 | /** 15 | * Created by kaede on 2015/5/24. 16 | */ 17 | public class BitmapUtil { 18 | 19 | private static final String TAG = "BitmapUtil"; 20 | 21 | public static Bitmap zoomBitmapToWidth(Bitmap bitmap, int width) { 22 | Log.e(TAG,"[kaede][zoomBitmapToWidth] width="+width); 23 | Matrix matrix = new Matrix(); 24 | matrix.postScale((float) width / bitmap.getWidth(), (float) width / bitmap.getWidth()); 25 | return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 26 | 27 | } 28 | 29 | public static Bitmap zoomBitmapToHeight(Bitmap bitmap, int height) { 30 | Log.e(TAG,"[kaede][zoomBitmapToHeight] height="+height); 31 | Matrix matrix = new Matrix(); 32 | matrix.postScale((float) height / bitmap.getHeight(), (float) height / bitmap.getHeight()); 33 | return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 34 | 35 | } 36 | 37 | public static Boolean saveBitmapToSd(Bitmap bitmap,int quality,String path) { 38 | File imagePath = new File(path); 39 | if (!imagePath.exists()) try { 40 | imagePath.createNewFile(); 41 | } catch (IOException e) { 42 | Log.e(TAG,"[kaede] Create file fail!"); 43 | e.printStackTrace(); 44 | return false; 45 | } 46 | if (imagePath.delete()){ 47 | FileOutputStream fos; 48 | try { 49 | fos = new FileOutputStream(imagePath); 50 | bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fos); 51 | fos.flush(); 52 | fos.close(); 53 | return true; 54 | } catch (Exception e) { 55 | Log.e(TAG, e.getMessage(), e); 56 | return false; 57 | } 58 | }else { 59 | Log.e(TAG,"[kaede] Image had exist and can not be deleted!"); 60 | return false; 61 | } 62 | 63 | } 64 | 65 | public static Bitmap getViewBitmap(View view){ 66 | View rootView = view.getRootView(); 67 | view.invalidate(); 68 | rootView.setDrawingCacheEnabled(true); 69 | return rootView.getDrawingCache(); 70 | } 71 | 72 | public static Bitmap getBitmapFromView(View v,Boolean isUseDrawingCache) { 73 | if (v.getMeasuredHeight()<=0||v.getMeasuredWidth()<=0){ 74 | // Either this 75 | //int specWidth = View.MeasureSpec.makeMeasureSpec(parentWidth, View.MeasureSpec.AT_MOST);// Or this 76 | int specWidth = View.MeasureSpec.makeMeasureSpec(0 /* any */, View.MeasureSpec.UNSPECIFIED); 77 | int specHeight = View.MeasureSpec.makeMeasureSpec(0 /* any */, View.MeasureSpec.UNSPECIFIED); 78 | v.measure(specWidth, specHeight); 79 | int questionWidth = v.getMeasuredWidth(); 80 | int questionHeight = v.getMeasuredHeight(); 81 | Log.d(TAG, "[kaede][getBitmapFromView] questionWidth = " + questionWidth + " questionHeight=" + questionHeight); 82 | v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); 83 | } 84 | return getBitmapFromVisiableView(v, isUseDrawingCache); 85 | } 86 | 87 | private static Bitmap getBitmapFromVisiableView(View view,Boolean isUseDrawingCache){ 88 | if (isUseDrawingCache){ 89 | View rootView = view.getRootView(); 90 | view.invalidate(); 91 | rootView.setDrawingCacheEnabled(true); 92 | return rootView.getDrawingCache(); 93 | } 94 | Bitmap b = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888); 95 | Canvas c = new Canvas(b); 96 | Drawable bgDrawable =view.getBackground(); 97 | if (bgDrawable!=null) 98 | bgDrawable.draw(c); 99 | //else c.drawColor(Color.TRANSPARENT); 100 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 101 | view.draw(c); 102 | return b; 103 | 104 | } 105 | 106 | public static Bitmap getScreenshot(Context context){ 107 | FileInputStream graphics = null; 108 | try { 109 | graphics = new FileInputStream("/dev/graphics/fb0"); 110 | } catch (FileNotFoundException e) { 111 | e.printStackTrace(); 112 | return null; 113 | } 114 | 115 | DisplayMetrics dm = new DisplayMetrics(); 116 | Display display =((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 117 | display.getMetrics(dm); 118 | int screenWidth = dm.widthPixels; // 屏幕宽(像素,如:480px) 119 | int screenHeight = dm.heightPixels; // 屏幕高(像素,如:800p) 120 | 121 | PixelFormat pixelFormat = new PixelFormat(); 122 | PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_8888, pixelFormat); 123 | int deepth = pixelFormat.bytesPerPixel; // 位深 124 | byte[] piex = new byte[screenHeight * screenWidth * deepth]; // 像素 125 | 126 | try { 127 | DataInputStream dStream = new DataInputStream(graphics); 128 | dStream.readFully(piex); 129 | dStream.close(); 130 | 131 | int[] colors = new int[screenHeight * screenWidth]; 132 | // 将rgb转为色值 133 | for (int m = 0; m < colors.length; m++) { 134 | int r = (piex[m * 4] & 0xFF); 135 | int g = (piex[m * 4 + 1] & 0xFF); 136 | int b = (piex[m * 4 + 2] & 0xFF); 137 | int a = (piex[m * 4 + 3] & 0xFF); 138 | colors[m] = (a << 24) + (r << 16) + (g << 8) + b; 139 | } 140 | 141 | return Bitmap.createBitmap(colors, screenWidth, screenHeight, 142 | Bitmap.Config.ARGB_8888); 143 | } catch (IOException e) { 144 | e.printStackTrace(); 145 | return null; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/util/FileUtil.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.util; 2 | 3 | import android.os.Environment; 4 | import android.util.Log; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by Kaede on 2015/5/25. 11 | */ 12 | public class FileUtil { 13 | 14 | private static final String TAG = "FileUtil"; 15 | 16 | public static String getSdpath(){ 17 | return Environment.getExternalStorageDirectory().getAbsolutePath(); 18 | } 19 | 20 | public static File getTempFile(String dir, String fieExtension) { 21 | String filePath = dir + File.separator + String.valueOf(System.currentTimeMillis()) + fieExtension; 22 | File file = new File(filePath); 23 | if (!file.exists()){ 24 | try { 25 | file.createNewFile(); 26 | } catch (IOException e) { 27 | Log.e(TAG,e.getMessage(),e ); 28 | return null; 29 | } 30 | } 31 | return file; 32 | 33 | } 34 | 35 | public static Boolean makeFile(String[] dirs) throws IOException { 36 | String path = getSdpath(); 37 | for (int i = 1; i <= dirs.length; i++) { 38 | if (i != dirs.length) { 39 | path = path + File.separator + dirs[i - 1]; 40 | File dir = new File(path); 41 | if (!dir.exists()) 42 | dir.mkdir(); 43 | } else { 44 | path = path + File.separator + dirs[i - 1]; 45 | File file = new File(path); 46 | if (!file.exists()) 47 | file.createNewFile(); 48 | } 49 | } 50 | return true; 51 | } 52 | 53 | public static File makeSdFile(String[] dirs) { 54 | String path = getSdpath(); 55 | try { 56 | for (int i = 1; i <= dirs.length; i++) { 57 | if (i != dirs.length) { 58 | path = path + File.separator + dirs[i - 1]; 59 | File dir = new File(path); 60 | if (!dir.exists()) 61 | dir.mkdir(); 62 | } else { 63 | path = path + File.separator + dirs[i - 1]; 64 | File file = new File(path); 65 | if (!file.exists()) 66 | file.createNewFile(); 67 | return file; 68 | } 69 | } 70 | } catch (Exception e) { 71 | Log.e(TAG, e.getMessage(), e); 72 | } 73 | 74 | return null; 75 | } 76 | 77 | 78 | 79 | public static String UriToFileName(String url, String replace) { 80 | return url.replaceAll("[/:\\\\|?*<>\"]", replace); 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/util/NavigationUtil.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.widget.Toast; 7 | 8 | /** 9 | * Created by kaede on 2015/5/27. 10 | */ 11 | public class NavigationUtil { 12 | public static void naviToMarket(Context context, String packageName) { 13 | Uri uri = Uri.parse("market://details?id=" + packageName); 14 | Intent it = new Intent(Intent.ACTION_VIEW, uri); 15 | try { 16 | context.startActivity(it); 17 | } catch (Exception e) { 18 | e.printStackTrace(); 19 | Toast.makeText(context, "找不到安卓市场", Toast.LENGTH_LONG).show();; 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/widget/AgeIndicatorLayout.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.ImageView; 13 | import android.widget.LinearLayout; 14 | import android.widget.TextView; 15 | import me.kaede.howoldrobot.R; 16 | import me.kaede.howoldrobot.analyse.model.Face; 17 | import me.kaede.howoldrobot.util.BitmapUtil; 18 | 19 | import java.util.Iterator; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by kaede on 2015/5/23. 24 | */ 25 | public class AgeIndicatorLayout extends LinearLayout { 26 | private static final String TAG = "AgeIndicatorLayout"; 27 | Boolean isDrawFace = false; 28 | List faces; 29 | Paint paint; 30 | private int xOffset; 31 | private int yOffset; 32 | 33 | private void init(){ 34 | this.isDrawFace = false; 35 | paint = new Paint(); 36 | paint.setStyle(Paint.Style.STROKE); 37 | paint.setColor(Color.WHITE); 38 | } 39 | public AgeIndicatorLayout(Context context) { 40 | super(context); 41 | init(); 42 | } 43 | 44 | public AgeIndicatorLayout(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | init(); 47 | } 48 | 49 | @Override 50 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 51 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 52 | init(); 53 | } 54 | 55 | @Override 56 | protected void onDraw(Canvas canvas) { 57 | super.onDraw(canvas); 58 | if (isDrawFace&&faces!=null){ 59 | Iterator iterator = faces.iterator(); 60 | while (iterator.hasNext()){ 61 | Face item = iterator.next(); 62 | //draw age indicator 63 | View ageIndicateView = LayoutInflater.from(getContext().getApplicationContext()).inflate(R.layout.item_age_indicator, null); 64 | if (ageIndicateView!=null){ 65 | TextView tvAge = (TextView) ageIndicateView.findViewById(R.id.tv_ageindicator_age); 66 | tvAge.setText(String.valueOf(item.attributes.age)); 67 | ImageView ivGender = (ImageView) ageIndicateView.findViewById(R.id.iv_ageindicator_gender); 68 | if (item.attributes.gender.equalsIgnoreCase("Male")){ 69 | ivGender.setImageResource(R.drawable.icon_gende_male); 70 | }else if(item.attributes.gender.equalsIgnoreCase("Female")){ 71 | ivGender.setImageResource(R.drawable.icon_gender_female); 72 | } 73 | Bitmap bitmap = BitmapUtil.getBitmapFromView(ageIndicateView,true); 74 | if (bitmap != null) { 75 | //BitmapUtil.saveBitmapToSd(bitmap, 100, Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp.jpg"); 76 | canvas.drawBitmap(bitmap,item.faceRectangle.left+xOffset - (ageIndicateView.getMeasuredWidth() - item.faceRectangle.width)/2,item.faceRectangle.top+yOffset-bitmap.getHeight(),paint); 77 | } 78 | Log.i(TAG, "ageIndicateView getMeasuredHeight()= " + ageIndicateView.getMeasuredHeight() + " getHeight=" + ageIndicateView.getHeight()); 79 | 80 | } 81 | } 82 | 83 | } 84 | } 85 | 86 | 87 | public void drawAges( List faces,int xOffset,int yOffset){ 88 | this.faces = faces; 89 | this.isDrawFace = true; 90 | this.xOffset = xOffset; 91 | this.yOffset = yOffset; 92 | invalidate(); 93 | } 94 | 95 | public void clearAges(){ 96 | this.faces = null; 97 | this.isDrawFace = false; 98 | invalidate(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/howoldrobot/widget/FaceImageView.java: -------------------------------------------------------------------------------- 1 | package me.kaede.howoldrobot.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.util.AttributeSet; 8 | import android.widget.ImageView; 9 | 10 | import java.util.Iterator; 11 | import java.util.List; 12 | 13 | import me.kaede.howoldrobot.analyse.model.Face; 14 | 15 | /** 16 | * Created by kaede on 2015/5/23. 17 | */ 18 | public class FaceImageView extends ImageView{ 19 | private static final String TAG = "FaceImageView"; 20 | Boolean isDrawFace = false; 21 | List faces; 22 | private int width; 23 | private int height; 24 | private Paint paint; 25 | 26 | public FaceImageView(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | public FaceImageView(Context context, AttributeSet attrs) { 32 | super(context, attrs); 33 | init(); 34 | } 35 | 36 | public FaceImageView(Context context, AttributeSet attrs, int defStyleAttr) { 37 | super(context, attrs, defStyleAttr); 38 | init(); 39 | } 40 | 41 | private void init(){ 42 | this.isDrawFace = false; 43 | paint = new Paint(); 44 | paint.setStyle(Paint.Style.STROKE); 45 | paint.setColor(Color.WHITE); 46 | } 47 | 48 | @Override 49 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 50 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 51 | width = getMeasuredWidth(); 52 | height = getMeasuredHeight(); 53 | } 54 | 55 | @Override 56 | protected void onDraw(Canvas canvas) { 57 | super.onDraw(canvas); 58 | if (isDrawFace&&faces!=null){ 59 | Iterator iterator = faces.iterator(); 60 | while (iterator.hasNext()){ 61 | Face item = iterator.next(); 62 | //draw rect 63 | canvas.drawRect(item.faceRectangle.left,item.faceRectangle.top,item.faceRectangle.left+item.faceRectangle.width,item.faceRectangle.top+item.faceRectangle.height, paint); 64 | } 65 | 66 | } 67 | } 68 | 69 | public void drawFaces( List faces){ 70 | this.faces = faces; 71 | this.isDrawFace = true; 72 | invalidate(); 73 | } 74 | 75 | public void clearFaces(){ 76 | this.faces = null; 77 | this.isDrawFace = false; 78 | invalidate(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_button_round.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xhdpi/bg_button_round.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_how_old_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xhdpi/icon_how_old_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_indicator.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/bg_indicator.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/cardui_round_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/cardui_round_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_camera.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_gallery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_gallery.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_gende_male.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_gende_male.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_gender_female.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_gender_female.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/app/src/main/res/drawable-xxhdpi/icon_share.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_bg_button_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_browser.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 14 | 20 | 21 | 24 | 36 | 41 | 46 | 47 | 48 | 49 | 60 | 66 | 72 | 78 | 87 | 96 | 105 | 106 | 107 | 108 | 119 | 128 | 130 | 136 | 137 | 147 | 149 | 155 | 156 | 157 | 166 | 168 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_browser.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_age_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 16 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_browser.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 20 | 21 | 27 | 28 | 31 | 32 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 年龄相机 3 | 年龄相机 4 | 5 | 分析中… 6 | 无法打开相机 7 | 无法打开图库 8 | 获取图片失败 9 | 图片分析失败 10 | 没有找到脸蛋哦 11 | 相机 12 | 图库 13 | 分享 14 | ① 从相机或者图库获取一张图片 15 | ② 会自动分析图片中脸蛋的性别年龄 16 | ③ 别忘了跟小伙伴们分享图片分析的结果 17 | 18 | 5星好评 19 | 搜索脸蛋 20 | 反馈 21 | 22 | 没有找到分享APP 23 | 选择APP 24 | 25 | Hello world! 26 | Settings 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF9800 4 | #FFCC80 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 5dp 6 | 5dp 7 | 3dp 8 | 10dp 9 | 49dp 10 | 40dp 11 | 70dp 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | How Old You Look 3 | HOW OLD 4 | 5 | Analysing… 6 | Open camera fail 7 | Pick photo fail 8 | Get image fail 9 | Analyze fail 10 | Find no face 11 | CAMERA 12 | GALLERY 13 | SHARE 14 | ① pick a photo from camera or gallery 15 | ② wait for analyse to get age and gender 16 | ③ don\'t forget to share with your peers 17 | 18 | Five Star 19 | Search Face 20 | Feedback 21 | 22 | Can\'t find Share APP 23 | Select APP 24 | 25 | Hello world! 26 | Settings 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 17 | 18 | 19 | 25 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.1.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/how-old-camera/f032a272d9482c9a0edc02d3c603819fa60d5275/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ###Demo Apk 2 | [Google Play](https://play.google.com/store/apps/details?id=me.kaede.howoldrobot) 3 | 4 | ###Description 5 | An android application for Microsoft how-old.net, as Example usage for Android `MVP` design pattern and `android-async-http` 6 | 7 | ###ScreenShot 8 | ![图片描述](https://dn-raysnote.qbox.me/p%2Fnotes%2Fd8d9deb8aad59b6 "图片标题") 9 | 10 | ![图片描述](https://dn-raysnote.qbox.me/p%2Fnotes%2F6e37e41d66dee09 "图片标题") 11 | 12 | ![图片描述](https://dn-raysnote.qbox.me/p%2Fnotes%2Fc5448084f9a363d "图片标题") 13 | 14 | ![图片描述](https://dn-raysnote.qbox.me/p%2Fnotes%2Fd4fcafbb2409033 "图片标题") 15 | 16 | ![图片描述](https://dn-raysnote.qbox.me/p%2Fnotes%2F46f2e9bafcc4dfe "图片标题") -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------