├── .gitignore ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── studio │ │ └── androiddev │ │ └── puzzle │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── studio │ │ │ └── androiddev │ │ │ └── puzzle │ │ │ ├── PuzzleApplication.java │ │ │ ├── activity │ │ │ ├── ActivityManager.java │ │ │ ├── BaseActivity.java │ │ │ ├── ChangePwdActivity.java │ │ │ ├── ChoosePicActivity.java │ │ │ ├── GameActivity.java │ │ │ ├── LoginActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── RankActivity.java │ │ │ ├── RegisterActivity.java │ │ │ ├── SettingActivity.java │ │ │ └── UserInfoActivity.java │ │ │ ├── adapter │ │ │ └── ChoosePicGridViewAdapter.java │ │ │ ├── bgm │ │ │ └── MusicServer.java │ │ │ ├── db │ │ │ └── DBHelper.java │ │ │ ├── dish │ │ │ ├── DishManager.java │ │ │ └── DragImageView.java │ │ │ ├── event │ │ │ ├── DishManagerInitFinishEvent.java │ │ │ ├── DishManagerInitStartEvent.java │ │ │ ├── GameSuccessEvent.java │ │ │ ├── PieceMoveSuccessEvent.java │ │ │ └── TimeEvent.java │ │ │ ├── imagesplit │ │ │ ├── ImagePiece.java │ │ │ ├── ImageSplitter.java │ │ │ └── Uri2FilePath.java │ │ │ ├── model │ │ │ ├── Record.java │ │ │ └── User.java │ │ │ └── utils │ │ │ ├── BitmapUtils.java │ │ │ ├── DensityUtil.java │ │ │ ├── GameTimer.java │ │ │ ├── GlobalUtils.java │ │ │ ├── RegExUtil.java │ │ │ ├── SecurityUtils.java │ │ │ └── StaticValue.java │ └── res │ │ ├── drawable │ │ ├── appearing.xml │ │ ├── button_background.xml │ │ ├── button_shape_bottom.xml │ │ ├── button_shape_top.xml │ │ ├── default1.jpg │ │ ├── default2.jpg │ │ ├── default3.jpg │ │ ├── default4.jpg │ │ ├── default5.jpg │ │ ├── default6.jpg │ │ ├── disappearing.xml │ │ ├── dish_background.xml │ │ ├── dish_shape_bottom.xml │ │ ├── dish_shape_middle.xml │ │ ├── dish_shape_top.xml │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_launcher.png │ │ ├── person_background.xml │ │ ├── person_shape_bottom.xml │ │ ├── person_shape_top.xml │ │ └── puzzle_en.png │ │ ├── layout │ │ ├── activity_change_pwd.xml │ │ ├── activity_choose_pic.xml │ │ ├── activity_game.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_rank.xml │ │ ├── activity_register.xml │ │ ├── activity_setting.xml │ │ ├── activity_user_info.xml │ │ ├── choose_pic_gridview_item.xml │ │ ├── content_change_pwd.xml │ │ ├── content_choose_pic.xml │ │ ├── content_game.xml │ │ ├── content_main.xml │ │ ├── content_rank.xml │ │ ├── content_setting.xml │ │ ├── content_user_info.xml │ │ ├── game_success.xml │ │ ├── layout_alertdiag.xml │ │ ├── layout_lv_rank.xml │ │ ├── layout_record.xml │ │ └── toolbar_main.xml │ │ ├── menu │ │ └── menu_user_info.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ ├── again.png │ │ ├── back.png │ │ ├── button_begin.png │ │ ├── button_exit.png │ │ ├── button_rank.png │ │ ├── button_setting.png │ │ ├── change_pwd.png │ │ ├── denglu.png │ │ ├── finish.png │ │ ├── help.png │ │ ├── ic_launcher.png │ │ ├── input.png │ │ ├── lock.png │ │ ├── loginbg.png │ │ ├── logo.png │ │ ├── logoff.png │ │ ├── share.png │ │ ├── time.png │ │ ├── user.png │ │ └── zhuce.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── studio │ └── androiddev │ └── puzzle │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── puzzle.iml___jb_bak___ └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | /.idea/ 8 | /app/src/main/res/raw/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 FreedomZZQ & haze & YouJoin Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 拼了个图 2 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_logo.png?imageView/2/w/400) 3 | 4 | ## 简介 5 | **拼了个图**是一款Android平台上的拼图小游戏。 6 | This repo is an awesome puzzle game on Android platform. 7 | 编译源码前,请先[下载](http://7vzrj0.com1.z0.glb.clouddn.com/puzzlebgm.rar)背景音乐文件,解压放到*/app/src/main/res/raw/*目录下。 8 | Before you build this repo, you should download [bgm](http://7vzrj0.com1.z0.glb.clouddn.com/puzzlebgm.rar) file and unzip it into */app/src/main/res/raw/* directory. 9 | ## 界面截图 10 | #### 登录页 11 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_login.png?imageView/2/w/400) 12 | #### 主界面 13 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_main.png?imageView/2/w/400) 14 | #### 关卡选择 15 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_choosepic.png?imageView/2/w/400) 16 | #### 游戏界面 17 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_game.png?imageView/2/w/400) 18 | #### 游戏胜利 19 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_success.png?imageView/2/w/400) 20 | #### 发现(最新的游戏记录) 21 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_ground.png?imageView/2/w/400) 22 | #### 设置和分享 23 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_setting.png?imageView/2/w/400) 24 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_share.png?imageView/2/w/400) 25 | #### 个人中心 26 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_person.png?imageView/2/w/400) 27 | 28 | ## 设计图 29 | ![](http://7vzrj0.com1.z0.glb.clouddn.com/puzzle_design.jpg?imageView/2/w/800) 30 | 31 | ## 协议 32 | The MIT License (MIT) 33 | 34 | Copyright (c) 2016 FreedomZZQ & haze & YouJoin Studio 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | 54 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "studio.androiddev.puzzle" 9 | minSdkVersion 19 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | compile 'com.android.support:design:23.1.1' 27 | compile 'com.jakewharton:butterknife:7.0.1' 28 | compile 'com.squareup.okhttp:okhttp:2.4.0' 29 | compile 'com.squareup.okio:okio:1.4.0' 30 | //bmob-sdk :Bmob的android sdk包 31 | compile 'cn.bmob.android:bmob-sdk:3.4.5' 32 | 33 | compile 'com.google.android.gms:play-services-appindexing:8.1.0' 34 | 35 | compile 'org.greenrobot:eventbus:3.0.0' 36 | 37 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2' 38 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 39 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 40 | } 41 | -------------------------------------------------------------------------------- /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 C:\Users\ZQ\AppData\Local\Android\sdk/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 | 19 | # --------------------------General---------------------------- 20 | -optimizationpasses 5 21 | -dontusemixedcaseclassnames 22 | -dontskipnonpubliclibraryclasses 23 | # -dontskipnonpubliclibraryclassmembers 24 | -dontpreverify 25 | -verbose 26 | -printmapping proguardMapping.txt 27 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 28 | -keepattributes *Annotation* 29 | -keepattributes Signature 30 | -keepattributes SourceFile,LineNumberTable 31 | -keepclasseswithmembernames class * { 32 | native ; 33 | } 34 | -keep public class * extends android.app.Activity 35 | -keep public class * extends android.app.Application 36 | -keep public class * extends android.app.Service 37 | -keep public class * extends android.content.BroadcastReceiver 38 | -keep public class * extends android.content.ContentProvider 39 | -keep public class * extends android.app.backup.BackupAgentHelper 40 | -keep public class * extends android.preference.Preference 41 | -keep public class * extends android.view.View 42 | -keep public class com.android.vending.licensing.ILicensingService 43 | -keep public class com.tuniu.app.ui.fragment.** {*;} 44 | 45 | -keepclassmembers class * extends android.app.Activity{ 46 | public void *(android.view.View); 47 | } 48 | 49 | -keepclassmembers enum * { 50 | public static **[] values(); 51 | public static ** valueOf(java.lang.String); 52 | } 53 | 54 | -keep public class * extends android.view.View { 55 | *** get*(); 56 | void set*(***); 57 | public (android.content.Context); 58 | public (android.content.Context, android.util.AttributeSet); 59 | public (android.content.Context, android.util.AttributeSet, int); 60 | } 61 | 62 | -keep class * implements android.os.Parcelable { 63 | public static final android.os.Parcelable$Creator *; 64 | } 65 | 66 | -keepclassmembers class * implements java.io.Serializable { 67 | static final long serialVersionUID; 68 | private static final java.io.ObjectStreamField[] serialPersistentFields; 69 | private void writeObject(java.io.ObjectOutputStream); 70 | private void readObject(java.io.ObjectInputStream); 71 | java.lang.Object writeReplace(); 72 | java.lang.Object readResolve(); 73 | } 74 | 75 | -keep class **.R$* { 76 | *; 77 | } 78 | 79 | -keepclassmembers class * { 80 | void *(**On*Event); 81 | } 82 | 83 | # 不混淆实体类 84 | -keep public class studio.androiddev.puzzle.model.** { 85 | *; 86 | } 87 | 88 | # --------------------------EventBus 3.0---------------------------- 89 | -keepattributes *Annotation* 90 | -keepclassmembers class ** { 91 | @org.greenrobot.eventbus.Subscribe ; 92 | } 93 | -keep enum org.greenrobot.eventbus.ThreadMode { *; } 94 | 95 | # Only required if you use AsyncExecutor 96 | -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { 97 | (java.lang.Throwable); 98 | } 99 | 100 | 101 | # --------------------------ButterKnife---------------------------- 102 | -keep class butterknife.** { *; } 103 | -dontwarn butterknife.internal.** 104 | -keep class **$$ViewBinder { *; } 105 | 106 | -keepnames class * { @butterknife.Bind *;} 107 | 108 | -keepclasseswithmembernames class * { 109 | @butterknife.* ; 110 | } 111 | 112 | -keepclasseswithmembernames class * { 113 | @butterknife.* ; 114 | } 115 | 116 | 117 | # --------------------------Bmob---------------------------- 118 | -ignorewarnings 119 | 120 | -keepattributes Signature 121 | 122 | # 不混淆BmobSDK 123 | -keep class cn.bmob.v3.** {*;} 124 | 125 | # 保证继承自BmobObject、BmobUser类的JavaBean不被混淆 126 | -keep class * extends cn.bmob.v3.BmobObject { 127 | *; 128 | } 129 | -keep class studio.androiddev.puzzle.model.Record{*;} 130 | -keep class studio.androiddev.puzzle.model.User{*;} 131 | 132 | # 如果你使用了okhttp、okio的包,请添加以下混淆代码 133 | -dontwarn com.squareup.okhttp.** 134 | -keep class com.squareup.okhttp.** { *;} 135 | -keep interface com.squareup.okhttp.** { *; } 136 | -dontwarn okio.** 137 | 138 | # 如果你需要兼容6.0系统,请不要混淆org.apache.http.legacy.jar 139 | -dontwarn android.net.compatibility.** 140 | -dontwarn android.net.http.** 141 | -dontwarn com.android.internal.http.multipart.** 142 | -dontwarn org.apache.commons.** 143 | -dontwarn org.apache.http.** 144 | -keep class android.net.compatibility.**{*;} 145 | -keep class android.net.http.**{*;} 146 | -keep class com.android.internal.http.multipart.**{*;} 147 | -keep class org.apache.commons.**{*;} 148 | -keep class org.apache.http.**{*;} -------------------------------------------------------------------------------- /app/src/androidTest/java/studio/androiddev/puzzle/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 41 | 44 | 48 | 52 | 56 | 57 | 58 | 59 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/PuzzleApplication.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | 7 | import com.squareup.leakcanary.LeakCanary; 8 | 9 | import cn.bmob.v3.Bmob; 10 | import studio.androiddev.puzzle.dish.DishManager; 11 | import studio.androiddev.puzzle.model.User; 12 | import studio.androiddev.puzzle.utils.StaticValue; 13 | 14 | /** 15 | * Puzzle 16 | * Created by ZQ on 2016/3/21. 17 | */ 18 | public class PuzzleApplication extends Application{ 19 | 20 | private static Context mContext; 21 | 22 | private static User mUser; 23 | 24 | private static DishManager dm; 25 | 26 | public static int getLevel() { 27 | return level; 28 | } 29 | 30 | public static void setLevel(int level) { 31 | if(level < 3) return; 32 | PuzzleApplication.level = level; 33 | initDishManager(); 34 | } 35 | 36 | private static int level = 4; 37 | 38 | @Override 39 | public void onCreate(){ 40 | super.onCreate(); 41 | LeakCanary.install(this); 42 | Bmob.initialize(this, StaticValue.bmobId); 43 | if(mContext == null) mContext = getApplicationContext(); 44 | SharedPreferences pref = getSharedPreferences(StaticValue.SP_NAME, MODE_PRIVATE); 45 | setLevel(pref.getInt(StaticValue.SP_LEVEL, 4)); 46 | } 47 | 48 | public static User getmUser() { 49 | return mUser; 50 | } 51 | 52 | public static void setmUser(User mUser) { 53 | PuzzleApplication.mUser = mUser; 54 | } 55 | 56 | public static Context getAppContext(){ 57 | return mContext; 58 | } 59 | 60 | public static void initDishManager(){ 61 | dm = new DishManager(level); 62 | } 63 | 64 | public static DishManager getDishManager(){ 65 | return dm; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/ActivityManager.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.app.Activity; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * The manager to manage activities 10 | * Puzzle 11 | * Created by ZQ on 2016/3/24. 12 | */ 13 | public class ActivityManager { 14 | 15 | /** 16 | * A list that holds all activities. 17 | */ 18 | public static List activities = new ArrayList<>(); 19 | 20 | /** 21 | * Add Activity to the list. 22 | * @param activity The Activity you want to add in. 23 | */ 24 | public static void addActivity(Activity activity){ activities.add(activity); } 25 | 26 | /** 27 | * Remove Activity from the list. 28 | * @param activity The Activity you want to remove. 29 | */ 30 | public static void removeActivity(Activity activity){ activities.remove(activity); } 31 | 32 | /** 33 | * Finish all the activities to finish the app. 34 | */ 35 | public static void finishAll(){ 36 | for(Activity activity : activities){ 37 | if(!activity.isFinishing()){ 38 | activity.finish(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | public abstract class BaseActivity extends AppCompatActivity { 7 | 8 | protected static final String TAG = "puzzle"; 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | ActivityManager.addActivity(this); 14 | } 15 | 16 | @Override 17 | protected void onDestroy() { 18 | super.onDestroy(); 19 | ActivityManager.removeActivity(this); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/ChangePwdActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.Toolbar; 7 | import android.util.Log; 8 | import android.view.MenuItem; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | import android.widget.Toast; 12 | 13 | import butterknife.Bind; 14 | import butterknife.ButterKnife; 15 | import butterknife.OnClick; 16 | import cn.bmob.v3.listener.UpdateListener; 17 | import studio.androiddev.puzzle.PuzzleApplication; 18 | import studio.androiddev.puzzle.R; 19 | import studio.androiddev.puzzle.model.User; 20 | import studio.androiddev.puzzle.utils.SecurityUtils; 21 | 22 | public class ChangePwdActivity extends BaseActivity { 23 | @Bind(R.id.et_pwd_old) 24 | EditText met_oldPwd; 25 | @Bind(R.id.et_pwd_new) 26 | EditText met_newPwd; 27 | @Bind(R.id.et_confirm_new_pwd) 28 | EditText met_confirmPwd; 29 | @Bind(R.id.btn_changePwd_confirm) 30 | Button mbtn_confirmChangePwd; 31 | @Bind(R.id.toolbar) 32 | Toolbar toolbar; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_change_pwd); 38 | ButterKnife.bind(this); 39 | setSupportActionBar(toolbar); 40 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 41 | 42 | } 43 | 44 | @Override 45 | public boolean onOptionsItemSelected(MenuItem item) { 46 | 47 | if (item.getItemId() == android.R.id.home) { 48 | finish(); 49 | return true; 50 | } 51 | 52 | return super.onOptionsItemSelected(item); 53 | } 54 | 55 | @OnClick(R.id.btn_changePwd_confirm) 56 | public void onClick() { 57 | String oldPwd = SecurityUtils.MD5_secure(met_oldPwd.getText().toString()); 58 | String newPwd = met_newPwd.getText().toString(); 59 | String newConPwd = met_confirmPwd.getText().toString(); 60 | User mUser = PuzzleApplication.getmUser(); 61 | if (mUser.getPwd().equals(oldPwd)) { 62 | if (newPwd.equals(newConPwd)) { 63 | String s = SecurityUtils.MD5_secure(newPwd); 64 | mUser.setPwd(s); 65 | mUser.update(ChangePwdActivity.this, mUser.getObjectId(), new UpdateListener() { 66 | @Override 67 | public void onSuccess() { 68 | Toast.makeText(ChangePwdActivity.this, "修改密码成功", Toast.LENGTH_SHORT).show(); 69 | Intent intent = new Intent(); 70 | setResult(333, intent); 71 | finish(); 72 | } 73 | 74 | @Override 75 | public void onFailure(int i, String s) { 76 | Log.e("main", s); 77 | } 78 | }); 79 | } else { 80 | met_confirmPwd.setError("密码输入不一致"); 81 | } 82 | } else { 83 | Toast.makeText(ChangePwdActivity.this, "原密码输入错误,请重新输入!", Toast.LENGTH_SHORT).show(); 84 | } 85 | } 86 | 87 | public static void actionStart(Activity context) { 88 | Intent intent = new Intent(context, ChangePwdActivity.class); 89 | context.startActivityForResult(intent, 1234); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/ChoosePicActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | import android.widget.GridView; 11 | 12 | import butterknife.Bind; 13 | import butterknife.ButterKnife; 14 | import studio.androiddev.puzzle.R; 15 | import studio.androiddev.puzzle.adapter.ChoosePicGridViewAdapter; 16 | 17 | public class ChoosePicActivity extends BaseActivity { 18 | 19 | @Bind(R.id.toolbar) 20 | Toolbar toolbar; 21 | @Bind(R.id.picContainer) 22 | GridView picContainer; 23 | 24 | public static final int [] icons={ 25 | R.drawable.default1, 26 | R.drawable.default2, 27 | R.drawable.default3, 28 | R.drawable.default4, 29 | R.drawable.default5, 30 | R.drawable.default6 31 | }; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_choose_pic); 37 | ButterKnife.bind(this); 38 | setSupportActionBar(toolbar); 39 | initView(); 40 | 41 | } 42 | 43 | private void initView() { 44 | 45 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 46 | 47 | picContainer.setAdapter(new ChoosePicGridViewAdapter(ChoosePicActivity.this, R.layout.choose_pic_gridview_item)); 48 | picContainer.setOnItemClickListener(new AdapterView.OnItemClickListener() { 49 | @Override 50 | public void onItemClick(AdapterView parent, View view, int position, long id) { 51 | 52 | GameActivity.actionStart(ChoosePicActivity.this, position); 53 | 54 | } 55 | }); 56 | } 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(MenuItem item) { 60 | if (item.getItemId() == android.R.id.home) { 61 | finish(); 62 | return true; 63 | } 64 | return super.onOptionsItemSelected(item); 65 | } 66 | 67 | public static void actionStart(Context context) { 68 | Intent intent = new Intent(context, ChoosePicActivity.class); 69 | context.startActivity(intent); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/GameActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.Bitmap; 7 | import android.os.Bundle; 8 | import android.os.Handler; 9 | import android.os.Message; 10 | import android.support.v7.widget.Toolbar; 11 | import android.util.Log; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.view.ViewStub; 15 | import android.widget.HorizontalScrollView; 16 | import android.widget.ImageButton; 17 | import android.widget.ImageView; 18 | import android.widget.LinearLayout; 19 | import android.widget.TextView; 20 | 21 | import org.greenrobot.eventbus.EventBus; 22 | import org.greenrobot.eventbus.Subscribe; 23 | import org.greenrobot.eventbus.ThreadMode; 24 | 25 | import java.io.FileNotFoundException; 26 | import java.lang.ref.WeakReference; 27 | import java.util.HashMap; 28 | import java.util.List; 29 | 30 | import butterknife.Bind; 31 | import butterknife.ButterKnife; 32 | import cn.bmob.v3.listener.SaveListener; 33 | import studio.androiddev.puzzle.PuzzleApplication; 34 | import studio.androiddev.puzzle.R; 35 | import studio.androiddev.puzzle.bgm.MusicServer; 36 | import studio.androiddev.puzzle.dish.DishManager; 37 | import studio.androiddev.puzzle.dish.DragImageView; 38 | import studio.androiddev.puzzle.event.DishManagerInitFinishEvent; 39 | import studio.androiddev.puzzle.event.GameSuccessEvent; 40 | import studio.androiddev.puzzle.event.PieceMoveSuccessEvent; 41 | import studio.androiddev.puzzle.event.TimeEvent; 42 | import studio.androiddev.puzzle.imagesplit.ImagePiece; 43 | import studio.androiddev.puzzle.imagesplit.ImageSplitter; 44 | import studio.androiddev.puzzle.model.Record; 45 | import studio.androiddev.puzzle.utils.BitmapUtils; 46 | import studio.androiddev.puzzle.utils.DensityUtil; 47 | import studio.androiddev.puzzle.utils.GameTimer; 48 | import studio.androiddev.puzzle.utils.GlobalUtils; 49 | 50 | public class GameActivity extends BaseActivity { 51 | 52 | @Bind(R.id.toolbar) 53 | Toolbar toolbar; 54 | @Bind(R.id.dish) 55 | ImageView dish; 56 | @Bind(R.id.layViewContainer) 57 | LinearLayout layViewContainer; 58 | @Bind(R.id.gameContainer) 59 | LinearLayout gameContainer; 60 | @Bind(R.id.timeText) 61 | TextView timeText; 62 | @Bind(R.id.viewContainer) 63 | HorizontalScrollView viewContainer; 64 | 65 | private StaticHandler timeHandler = new StaticHandler(GameActivity.this); 66 | private GameTimer gameTimer; 67 | private int time = 0; 68 | 69 | private DishManager dm; 70 | private Bitmap mBitmap; 71 | 72 | private final int DISH_WIDTH = 300; 73 | private final int DISH_HEIGHT = 300; 74 | private HashMap pieceList = new HashMap<>(); 75 | private static final String PIC_INDEX = "picIndex"; 76 | 77 | private List IPL; 78 | 79 | @Override 80 | protected void onCreate(Bundle savedInstanceState) { 81 | super.onCreate(savedInstanceState); 82 | setContentView(R.layout.activity_game); 83 | ButterKnife.bind(this); 84 | setSupportActionBar(toolbar); 85 | EventBus.getDefault().register(this); 86 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 87 | gameTimer = new GameTimer(timeHandler); 88 | 89 | initialization(); 90 | EventBus.getDefault().post(new DishManagerInitFinishEvent()); 91 | 92 | } 93 | @Subscribe(threadMode = ThreadMode.MAIN) 94 | public void onEvent(TimeEvent event) { 95 | time++; 96 | 97 | int curminute = time / 60; 98 | int cursecond = time % 60; 99 | 100 | String curTimeString = String.format("%02d:%02d", curminute, cursecond); 101 | timeText.setText(curTimeString); 102 | } 103 | 104 | @Override 105 | protected void onStart() { 106 | super.onStart(); 107 | 108 | Intent intent = new Intent(GameActivity.this, MusicServer.class); 109 | startService(intent); 110 | 111 | } 112 | 113 | @Override 114 | protected void onResume() { 115 | super.onResume(); 116 | } 117 | 118 | @Override 119 | protected void onStop() { 120 | super.onStop(); 121 | Intent intent = new Intent(GameActivity.this, MusicServer.class); 122 | stopService(intent); 123 | 124 | } 125 | 126 | @Override 127 | protected void onDestroy() { 128 | super.onDestroy(); 129 | EventBus.getDefault().unregister(this); 130 | if(mBitmap != null && !mBitmap.isRecycled()){ 131 | mBitmap.recycle(); 132 | } 133 | 134 | dm.recycle(); 135 | 136 | if (IPL != null) { 137 | for (int i = 0; i < IPL.size(); i++) { 138 | IPL.get(i).recycleBitmap(); 139 | } 140 | IPL.clear(); 141 | IPL = null; 142 | } 143 | 144 | if(gameTimer != null){ 145 | gameTimer.recycle(); 146 | gameTimer = null; 147 | } 148 | 149 | System.gc(); 150 | } 151 | 152 | @Subscribe(threadMode = ThreadMode.MAIN) 153 | public void onEvent(PieceMoveSuccessEvent event) { 154 | int index = event.getIndex(); 155 | DragImageView view = (DragImageView) pieceList.get(index); 156 | if (view != null) { 157 | view.setVisibility(View.GONE); 158 | } 159 | } 160 | 161 | @Subscribe(threadMode = ThreadMode.MAIN) 162 | public void onEvent(GameSuccessEvent event) { 163 | 164 | gameTimer.stopTimer(); 165 | Record eTemp = new Record(); 166 | 167 | eTemp.setPhoneNum(PuzzleApplication.getmUser().getPhoneNum()); 168 | eTemp.setType(PuzzleApplication.getLevel() + ""); 169 | eTemp.setTime(timeText.getText().toString()); 170 | eTemp.setPic_url(PuzzleApplication.getmUser().getImgUrl()); 171 | eTemp.setNickname(PuzzleApplication.getmUser().getNickName()); 172 | 173 | eTemp.save(GameActivity.this, new SaveListener() { 174 | @Override 175 | public void onSuccess() { 176 | Log.i("main", "数据记录保存成功"); 177 | } 178 | 179 | @Override 180 | public void onFailure(int i, String s) { 181 | Log.e("main", "数据记录保存失败" + s); 182 | } 183 | }); 184 | 185 | showSuccess(); 186 | 187 | } 188 | 189 | private void showSuccess() { 190 | viewContainer.setVisibility(View.GONE); 191 | View successContainer = ((ViewStub) findViewById(R.id.success_stub)).inflate(); 192 | ImageView finishImage = (ImageView) successContainer.findViewById(R.id.finishImage); 193 | ImageButton againButton = (ImageButton) successContainer.findViewById(R.id.againButton); 194 | 195 | finishImage.setVisibility(View.VISIBLE); 196 | againButton.setVisibility(View.VISIBLE); 197 | 198 | againButton.setOnClickListener(new View.OnClickListener() { 199 | @Override 200 | public void onClick(View v) { 201 | finish(); 202 | } 203 | }); 204 | 205 | } 206 | 207 | @Subscribe(threadMode = ThreadMode.MAIN) 208 | public void onEvent(DishManagerInitFinishEvent event) { 209 | gameTimer.startTimer(); 210 | } 211 | 212 | private void initialization() { 213 | Log.d(TAG, "init begin"); 214 | layViewContainer.removeAllViews(); 215 | pieceList.clear(); 216 | 217 | int picIndex = getIntent().getIntExtra(PIC_INDEX, 0); 218 | mBitmap = BitmapUtils.decodeSampledBitmapFromResources(getResources(), 219 | ChoosePicActivity.icons[picIndex], 220 | DISH_WIDTH, DISH_HEIGHT); 221 | dm = PuzzleApplication.getDishManager(); 222 | 223 | if (dm == null) return; 224 | 225 | dm.initNewGame(mBitmap, dish); 226 | 227 | Log.d(TAG, "DishManager init finish"); 228 | 229 | try { 230 | 231 | // TODO: 2016/4/27 裁剪算法优化基本完成,尚有几像素的偏差,可能是int到float强制转换的精度损失 232 | //IPL = ImageSplitter.split(mBitmap, PuzzleApplication.getLevel(), DISH_WIDTH, DISH_HEIGHT); 233 | int dishWidth = DensityUtil.dip2px(PuzzleApplication.getAppContext(), DISH_WIDTH); 234 | int dishHeight = DensityUtil.dip2px(PuzzleApplication.getAppContext(), DISH_HEIGHT); 235 | Bitmap tempBitmap = BitmapUtils.createNoRecycleScaleBitmap( 236 | mBitmap, 237 | dishWidth, 238 | dishHeight); 239 | IPL = ImageSplitter.split(tempBitmap, PuzzleApplication.getLevel(), 240 | dishWidth, 241 | dishHeight); 242 | tempBitmap.recycle(); 243 | Log.d(TAG, "split finish"); 244 | 245 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( 246 | LinearLayout.LayoutParams.WRAP_CONTENT, 247 | LinearLayout.LayoutParams.WRAP_CONTENT); 248 | layoutParams.setMarginEnd(20); 249 | 250 | int mLevel = PuzzleApplication.getLevel(); 251 | 252 | for (int i = 0; i < mLevel; i++) { 253 | for (int j = 0; j < mLevel; j++) { 254 | DragImageView imageView = new DragImageView(this); 255 | imageView.setLayoutParams(layoutParams); 256 | //imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); 257 | imageView.setImageBitmap(IPL.get(j + i * mLevel).bitmap); 258 | 259 | imageView.setIndex(j + i * mLevel); 260 | pieceList.put(imageView.getIndex(), imageView); 261 | } 262 | } 263 | 264 | int[] list = GlobalUtils.getRamdomList(mLevel * mLevel); 265 | 266 | if (layViewContainer != null) { 267 | for (int aList : list) { 268 | layViewContainer.addView(pieceList.get(aList), layoutParams); 269 | } 270 | 271 | } 272 | 273 | } catch (FileNotFoundException e) { 274 | e.printStackTrace(); 275 | } 276 | 277 | Log.d(TAG, "init finish"); 278 | } 279 | 280 | 281 | @Override 282 | public boolean onOptionsItemSelected(MenuItem item) { 283 | if (item.getItemId() == android.R.id.home) { 284 | finish(); 285 | return true; 286 | } 287 | return super.onOptionsItemSelected(item); 288 | } 289 | 290 | public static void actionStart(Context context, int picIndex) { 291 | Intent intent = new Intent(context, GameActivity.class); 292 | intent.putExtra(PIC_INDEX, picIndex); 293 | context.startActivity(intent); 294 | } 295 | 296 | public static class StaticHandler extends Handler { 297 | 298 | private final WeakReference mActivity; 299 | 300 | public StaticHandler(Activity activity){ 301 | mActivity = new WeakReference(activity); 302 | } 303 | 304 | 305 | @Override 306 | public void handleMessage(Message msg){ 307 | super.handleMessage(msg); 308 | switch (msg.what) { 309 | case GameTimer.MESSAGE_TIMER: 310 | EventBus.getDefault().post(new TimeEvent()); 311 | //refreshTimeText(); 312 | break; 313 | 314 | } 315 | } 316 | } 317 | } 318 | 319 | 320 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | import android.widget.ImageButton; 10 | import android.widget.Toast; 11 | 12 | import java.util.List; 13 | 14 | import butterknife.Bind; 15 | import butterknife.ButterKnife; 16 | import butterknife.OnClick; 17 | import cn.bmob.v3.BmobQuery; 18 | import cn.bmob.v3.listener.FindListener; 19 | import studio.androiddev.puzzle.PuzzleApplication; 20 | import studio.androiddev.puzzle.R; 21 | import studio.androiddev.puzzle.model.User; 22 | import studio.androiddev.puzzle.utils.RegExUtil; 23 | import studio.androiddev.puzzle.utils.SecurityUtils; 24 | 25 | public class LoginActivity extends BaseActivity { 26 | @Bind(R.id.et_phone) 27 | EditText met_phone; 28 | @Bind(R.id.et_pwd) 29 | EditText met_pwd; 30 | @Bind(R.id.btn_register) 31 | ImageButton mbtn_register; 32 | @Bind(R.id.btn_login) 33 | ImageButton mbtn_login; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | // Bmob.initialize(this, StaticValue.bmobId); 39 | setContentView(R.layout.activity_login); 40 | ButterKnife.bind(this); 41 | 42 | } 43 | 44 | @OnClick({R.id.btn_register, R.id.btn_login}) 45 | public void onClick(View view) { 46 | switch (view.getId()) { 47 | case R.id.btn_register: 48 | //注册按钮点击事件 49 | Intent intent = new Intent(LoginActivity.this, RegisterActivity.class); 50 | startActivity(intent); 51 | break; 52 | case R.id.btn_login: 53 | //登录按钮点击事件 54 | final String phone = met_phone.getText().toString(); 55 | final String pwd = met_pwd.getText().toString(); 56 | 57 | if (RegExUtil.confirmPhone(phone)) { 58 | if (RegExUtil.confirmPwd(pwd)) { 59 | 60 | // 登录验证逻辑函数 61 | BmobQuery query = new BmobQuery(); 62 | query.addWhereEqualTo("phoneNum", phone); 63 | query.findObjects(PuzzleApplication.getAppContext(), new FindListener() { 64 | @Override 65 | public void onSuccess(List list) { 66 | if (list.size() == 1) { 67 | String pwd_MD5_Bmob = list.get(0).getPwd(); 68 | String pwd_MD5_Local = SecurityUtils.MD5_secure(pwd); 69 | if (pwd_MD5_Bmob.equals(pwd_MD5_Local)) { 70 | //登陆成功后要做三件事: 71 | //1.更新Application中的User 72 | //2.启动MainActivity 73 | //3.清空输入框 74 | PuzzleApplication.setmUser(list.get(0)); 75 | MainActivity.actionStart(LoginActivity.this); 76 | met_phone.setText(""); 77 | met_pwd.setText(""); 78 | } else { 79 | Toast.makeText(LoginActivity.this, "输入密码错误,请重新输入!", Toast.LENGTH_SHORT).show(); 80 | } 81 | } else if (list.size() == 0) { 82 | Toast.makeText(LoginActivity.this, "不存在该账号,请注册!", Toast.LENGTH_SHORT).show(); 83 | } 84 | } 85 | 86 | @Override 87 | public void onError(int i, String s) { 88 | Log.e("main", s); 89 | } 90 | }); 91 | 92 | } else { 93 | met_pwd.setError("密码格式错误,请重新输入!"); 94 | } 95 | 96 | } else { 97 | met_phone.setError("手机号格式错误,请重新输入!"); 98 | } 99 | break; 100 | } 101 | } 102 | 103 | public static void actionStart(Context context){ 104 | Intent intent = new Intent(context, LoginActivity.class); 105 | context.startActivity(intent); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.KeyEvent; 8 | import android.view.View; 9 | import android.widget.ImageButton; 10 | import android.widget.Toast; 11 | 12 | import butterknife.Bind; 13 | import butterknife.ButterKnife; 14 | import butterknife.OnClick; 15 | import studio.androiddev.puzzle.PuzzleApplication; 16 | import studio.androiddev.puzzle.R; 17 | 18 | public class MainActivity extends BaseActivity { 19 | 20 | @Bind(R.id.beginButton) 21 | ImageButton beginButton; 22 | @Bind(R.id.rankButton) 23 | ImageButton rankButton; 24 | @Bind(R.id.settingButton) 25 | ImageButton settingButton; 26 | @Bind(R.id.exitButton) 27 | ImageButton exitButton; 28 | @Bind(R.id.toolbar) 29 | Toolbar toolbar; 30 | @Bind(R.id.userButton) 31 | ImageButton userButton; 32 | 33 | //用于记录两次按下返回键的间隔 34 | private long exitTime = 0; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_main); 40 | ButterKnife.bind(this); 41 | toolbar.setTitle(""); 42 | setSupportActionBar(toolbar); 43 | // PuzzleApplication.initDishManager(4); 44 | 45 | } 46 | 47 | @Override 48 | protected void onDestroy(){ 49 | super.onDestroy(); 50 | } 51 | 52 | @OnClick({R.id.beginButton, R.id.rankButton, R.id.settingButton, R.id.exitButton}) 53 | public void onClick(View view) { 54 | switch (view.getId()) { 55 | case R.id.beginButton: 56 | ChoosePicActivity.actionStart(MainActivity.this); 57 | break; 58 | case R.id.rankButton: 59 | RankActivity.actionStart(MainActivity.this); 60 | break; 61 | case R.id.settingButton: 62 | SettingActivity.actionStart(MainActivity.this); 63 | break; 64 | case R.id.exitButton: 65 | ActivityManager.finishAll(); 66 | break; 67 | } 68 | } 69 | 70 | 71 | 72 | @Override 73 | public boolean onKeyDown(int keyCode, KeyEvent event) { 74 | if (keyCode == KeyEvent.KEYCODE_BACK) { 75 | //在两秒内两次按下返回键退出程序 76 | if ((System.currentTimeMillis() - exitTime) > 2000) { 77 | Toast.makeText(MainActivity.this, getString(R.string.click_again_to_exit), Toast.LENGTH_SHORT).show(); 78 | exitTime = System.currentTimeMillis(); 79 | } else { 80 | ActivityManager.finishAll(); 81 | } 82 | return true; 83 | } 84 | return super.onKeyDown(keyCode, event); 85 | } 86 | 87 | public static void actionStart(Context context) { 88 | Intent intent = new Intent(context, MainActivity.class); 89 | context.startActivity(intent); 90 | } 91 | 92 | @OnClick(R.id.userButton) 93 | public void onClick() { 94 | UserInfoActivity.actionStart(MainActivity.this); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/RankActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.os.Bundle; 8 | import android.support.v7.widget.Toolbar; 9 | import android.util.Log; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.BaseAdapter; 14 | import android.widget.ImageView; 15 | import android.widget.ListView; 16 | import android.widget.TextView; 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | import java.net.HttpURLConnection; 20 | import java.net.MalformedURLException; 21 | import java.net.URL; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import butterknife.Bind; 26 | import butterknife.ButterKnife; 27 | import cn.bmob.v3.BmobQuery; 28 | import cn.bmob.v3.listener.FindListener; 29 | import studio.androiddev.puzzle.R; 30 | import studio.androiddev.puzzle.model.Record; 31 | 32 | public class RankActivity extends BaseActivity { 33 | 34 | @Bind(R.id.toolbar) 35 | Toolbar toolbar; 36 | 37 | ListView mlv_rank; 38 | List mRecSet; 39 | RankAdapter adapter; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_rank); 45 | ButterKnife.bind(this); 46 | setSupportActionBar(toolbar); 47 | 48 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 49 | 50 | mlv_rank= (ListView) findViewById(R.id.lv_rank); 51 | 52 | BmobQuery query = new BmobQuery<>(); 53 | query.order("-updatedAt"); 54 | query.setLimit(20); 55 | query.findObjects(this, new FindListener() { 56 | @Override 57 | public void onSuccess(List list) { 58 | mRecSet=list; 59 | adapter=new RankAdapter(mRecSet,RankActivity.this); 60 | mlv_rank.setAdapter(adapter); 61 | } 62 | 63 | @Override 64 | public void onError(int i, String s) { 65 | Log.e("main",s); 66 | } 67 | }); 68 | 69 | } 70 | 71 | class RankAdapter extends BaseAdapter{ 72 | 73 | ArrayList mSet; 74 | Context context; 75 | 76 | public RankAdapter(List mSett,Context mcontext) { 77 | mSet= (ArrayList) mSett; 78 | context=mcontext; 79 | } 80 | 81 | @Override 82 | public int getCount() { 83 | return mSet.size(); 84 | } 85 | 86 | @Override 87 | public Record getItem(int position) { 88 | return mSet.get(position); 89 | } 90 | 91 | @Override 92 | public long getItemId(int position) { 93 | return position; 94 | } 95 | 96 | @Override 97 | public View getView(final int position, View convertView, ViewGroup parent) { 98 | 99 | ViewHolder viewHolder = null; 100 | if (convertView == null) { 101 | convertView = View.inflate(context, R.layout.layout_lv_rank, null); 102 | viewHolder = new ViewHolder(); 103 | viewHolder.iv_t= (ImageView) convertView.findViewById(R.id.iv_user_pic); 104 | viewHolder.tv_nick= (TextView) convertView.findViewById(R.id.tv_nickname_rank); 105 | viewHolder.tv_level= (TextView) convertView.findViewById(R.id.tv_level); 106 | viewHolder.tv_gametime= (TextView) convertView.findViewById(R.id.tv_gametime); 107 | viewHolder.tv_uptime= (TextView) convertView.findViewById(R.id.tv_uptime); 108 | convertView.setTag(viewHolder); 109 | } else { 110 | viewHolder = (ViewHolder) convertView.getTag(); 111 | } 112 | 113 | // Log.i("main",mSet.toString()); 114 | 115 | if (!mSet.get(position).getPic_url().equals("null")) { 116 | 117 | final ViewHolder finalViewHolder = viewHolder; 118 | new Thread(new Runnable() { 119 | @Override 120 | public void run() { 121 | String imageUrl = mSet.get(position).getPic_url(); 122 | final Bitmap bitmap = returnBitMap(imageUrl); 123 | runOnUiThread(new Runnable() { 124 | @Override 125 | public void run() { 126 | finalViewHolder.iv_t.setImageBitmap(bitmap); 127 | } 128 | }); 129 | 130 | } 131 | }).start(); 132 | 133 | } 134 | 135 | String nicktt; 136 | if(!mSet.get(position).getNickname().equals("null")){ 137 | nicktt=mSet.get(position).getNickname(); 138 | }else { 139 | nicktt=mSet.get(position).getPhoneNum(); 140 | } 141 | viewHolder.tv_nick.setText(nicktt); 142 | 143 | viewHolder.tv_level.setText(mSet.get(position).getType() +" x "+mSet.get(position).getType()); 144 | 145 | viewHolder.tv_gametime.setText(mSet.get(position).getTime()); 146 | 147 | viewHolder.tv_uptime.setText(mSet.get(position).getUpdatedAt()); 148 | 149 | 150 | return convertView; 151 | } 152 | 153 | 154 | class ViewHolder { 155 | ImageView iv_t; 156 | TextView tv_nick; 157 | TextView tv_level; 158 | TextView tv_gametime; 159 | TextView tv_uptime; 160 | } 161 | 162 | } 163 | 164 | public Bitmap returnBitMap(String url) { 165 | URL myFileUrl = null; 166 | Bitmap bitmap = null; 167 | try { 168 | myFileUrl = new URL(url); 169 | } catch (MalformedURLException e) { 170 | e.printStackTrace(); 171 | } 172 | try { 173 | HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection(); 174 | conn.setDoInput(true); 175 | conn.connect(); 176 | InputStream is = conn.getInputStream(); 177 | bitmap = BitmapFactory.decodeStream(is); 178 | is.close(); 179 | } catch (IOException e) { 180 | e.printStackTrace(); 181 | } 182 | return bitmap; 183 | } 184 | 185 | 186 | @Override 187 | public boolean onOptionsItemSelected(MenuItem item) { 188 | if (item.getItemId() == android.R.id.home) { 189 | finish(); 190 | return true; 191 | } 192 | return super.onOptionsItemSelected(item); 193 | } 194 | 195 | public static void actionStart(Context context) { 196 | Intent intent = new Intent(context, RankActivity.class); 197 | context.startActivity(intent); 198 | } 199 | 200 | 201 | 202 | } 203 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/RegisterActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.widget.EditText; 6 | import android.widget.ImageButton; 7 | import android.widget.Toast; 8 | 9 | import java.util.Date; 10 | 11 | import butterknife.Bind; 12 | import butterknife.ButterKnife; 13 | import butterknife.OnClick; 14 | import cn.bmob.v3.datatype.BmobDate; 15 | import cn.bmob.v3.listener.SaveListener; 16 | import studio.androiddev.puzzle.R; 17 | import studio.androiddev.puzzle.model.User; 18 | import studio.androiddev.puzzle.utils.RegExUtil; 19 | import studio.androiddev.puzzle.utils.SecurityUtils; 20 | 21 | public class RegisterActivity extends BaseActivity { 22 | 23 | 24 | @Bind(R.id.et_phone_reg) 25 | EditText etPhoneReg; 26 | @Bind(R.id.et_pwd_register) 27 | EditText etPwdRegister; 28 | @Bind(R.id.et_pwd_confirm_register) 29 | EditText etPwdConfirmRegister; 30 | @Bind(R.id.btn_register_res) 31 | ImageButton btnRegisterRes; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_register); 37 | ButterKnife.bind(this); 38 | 39 | } 40 | 41 | private void regSaveInLocal(User user) { 42 | 43 | } 44 | 45 | private void regPushToBmob(User user) { 46 | 47 | user.save(this, new SaveListener() { 48 | @Override 49 | public void onSuccess() { 50 | Toast.makeText(RegisterActivity.this, "注册成功", Toast.LENGTH_LONG).show(); 51 | Intent intent = new Intent(RegisterActivity.this, LoginActivity.class); 52 | startActivity(intent); 53 | } 54 | 55 | @Override 56 | public void onFailure(int i, String s) { 57 | Toast.makeText(RegisterActivity.this, "数据存储失败,请检查网络", Toast.LENGTH_LONG).show(); 58 | } 59 | }); 60 | } 61 | 62 | 63 | @OnClick(R.id.btn_register_res) 64 | public void onClick() { 65 | if (RegExUtil.confirmPhone(etPhoneReg.getText().toString())) { 66 | if (RegExUtil.confirmPwd(etPwdRegister.getText().toString())) { 67 | if (etPwdRegister.getText().toString().equals(etPwdConfirmRegister.getText().toString())) { 68 | 69 | User temp = new User(); 70 | temp.setPhoneNum(etPhoneReg.getText().toString()); 71 | String pwd_MD5 = SecurityUtils.MD5_secure(etPwdRegister.getText().toString()); 72 | temp.setPwd(pwd_MD5); 73 | temp.setCreateTime(new BmobDate(new Date())); 74 | temp.setImgUrl("null"); 75 | temp.setMailNum("待添加"); 76 | temp.setNickName("待添加"); 77 | regPushToBmob(temp); 78 | regSaveInLocal(temp); 79 | 80 | } else { 81 | etPwdConfirmRegister.setError("两次密码输入不一致!"); 82 | } 83 | 84 | } else { 85 | etPwdRegister.setError("密码至少为8位数字或字符"); 86 | } 87 | 88 | } else { 89 | etPhoneReg.setError("手机号码格式错误"); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.os.Bundle; 9 | import android.support.v7.widget.Toolbar; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.widget.Button; 13 | import android.widget.ImageButton; 14 | 15 | import butterknife.Bind; 16 | import butterknife.ButterKnife; 17 | import butterknife.OnClick; 18 | import studio.androiddev.puzzle.PuzzleApplication; 19 | import studio.androiddev.puzzle.R; 20 | import studio.androiddev.puzzle.utils.StaticValue; 21 | 22 | public class SettingActivity extends BaseActivity { 23 | 24 | @Bind(R.id.toolbar) 25 | Toolbar toolbar; 26 | @Bind(R.id.levelChooseButton) 27 | Button levelChooseButton; 28 | @Bind(R.id.buttonShare) 29 | ImageButton buttonShare; 30 | 31 | private int choosedLevel = 0; 32 | 33 | final int[] levels = { 34 | R.string.setting_level_3, 35 | R.string.setting_level_4, 36 | R.string.setting_level_5, 37 | R.string.setting_level_6}; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_setting); 43 | ButterKnife.bind(this); 44 | setSupportActionBar(toolbar); 45 | 46 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 47 | levelChooseButton.setText(getString(levels[PuzzleApplication.getLevel() - 3])); 48 | 49 | } 50 | 51 | @Override 52 | public boolean onOptionsItemSelected(MenuItem item) { 53 | if (item.getItemId() == android.R.id.home) { 54 | finish(); 55 | return true; 56 | } 57 | return super.onOptionsItemSelected(item); 58 | } 59 | 60 | public static void actionStart(Context context) { 61 | Intent intent = new Intent(context, SettingActivity.class); 62 | context.startActivity(intent); 63 | } 64 | 65 | private void chooseLevel() { 66 | final AlertDialog.Builder builder = new AlertDialog.Builder(SettingActivity.this); 67 | 68 | final String[] levels = { 69 | getString(R.string.setting_level_3), 70 | getString(R.string.setting_level_4), 71 | getString(R.string.setting_level_5), 72 | getString(R.string.setting_level_6)}; 73 | 74 | builder.setTitle("请选择难度"); 75 | int defaultWhich = 0; 76 | 77 | for (int i = 0; i < levels.length; i++) { 78 | if (levelChooseButton.getText().toString().equals(levels[i])) { 79 | defaultWhich = i; 80 | } 81 | } 82 | 83 | builder.setSingleChoiceItems(levels, defaultWhich, 84 | new DialogInterface.OnClickListener() { 85 | @Override 86 | public void onClick(DialogInterface dialog, int which) { 87 | choosedLevel = which; 88 | } 89 | }); 90 | builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { 91 | @Override 92 | public void onClick(DialogInterface dialog, int which) { 93 | levelChooseButton.setText(levels[choosedLevel]); 94 | changeLevel(); 95 | } 96 | }); 97 | builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { 98 | @Override 99 | public void onClick(DialogInterface dialog, int which) { 100 | 101 | } 102 | }); 103 | builder.show(); 104 | } 105 | 106 | private void changeLevel() { 107 | 108 | int level = choosedLevel + 3; 109 | SharedPreferences.Editor editor = getSharedPreferences(StaticValue.SP_NAME, MODE_PRIVATE).edit(); 110 | editor.putInt(StaticValue.SP_LEVEL, level); 111 | editor.apply(); 112 | PuzzleApplication.setLevel(level); 113 | } 114 | 115 | private void shareAction(){ 116 | Intent shareIntent = new Intent(); 117 | shareIntent.setAction(Intent.ACTION_SEND); 118 | shareIntent.putExtra(Intent.EXTRA_TEXT, getResources().getString(R.string.setting_share)); 119 | shareIntent.setType("text/plain"); 120 | 121 | //设置分享列表的标题,并且每次都显示分享列表 122 | startActivity(Intent.createChooser(shareIntent, "分享到")); 123 | } 124 | 125 | @OnClick({R.id.levelChooseButton, R.id.buttonShare}) 126 | public void onClick(View view) { 127 | switch (view.getId()) { 128 | case R.id.levelChooseButton: 129 | chooseLevel(); 130 | break; 131 | case R.id.buttonShare: 132 | shareAction(); 133 | break; 134 | } 135 | } 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/activity/UserInfoActivity.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.activity; 2 | 3 | import android.app.AlertDialog; 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.os.Bundle; 10 | import android.os.Environment; 11 | import android.provider.MediaStore; 12 | import android.support.v7.widget.Toolbar; 13 | import android.util.Log; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.widget.BaseAdapter; 19 | import android.widget.EditText; 20 | import android.widget.ImageButton; 21 | import android.widget.ImageView; 22 | import android.widget.ListView; 23 | import android.widget.TextView; 24 | 25 | import java.io.File; 26 | import java.io.FileNotFoundException; 27 | import java.io.FileOutputStream; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.net.HttpURLConnection; 31 | import java.net.MalformedURLException; 32 | import java.net.URL; 33 | import java.util.List; 34 | 35 | import butterknife.Bind; 36 | import butterknife.ButterKnife; 37 | import butterknife.OnClick; 38 | import cn.bmob.v3.BmobQuery; 39 | import cn.bmob.v3.datatype.BmobFile; 40 | import cn.bmob.v3.listener.FindListener; 41 | import cn.bmob.v3.listener.UpdateListener; 42 | import cn.bmob.v3.listener.UploadFileListener; 43 | import studio.androiddev.puzzle.PuzzleApplication; 44 | import studio.androiddev.puzzle.R; 45 | import studio.androiddev.puzzle.model.Record; 46 | import studio.androiddev.puzzle.model.User; 47 | 48 | public class UserInfoActivity extends BaseActivity { 49 | 50 | private static int CAMERA_REQUEST_CODE = 1; 51 | private static int GALLERY_REQUEST_CODE = 2; 52 | private static int CROP_REQUEST_CODE = 3; 53 | 54 | private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";//temp file 55 | Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap 56 | 57 | @Bind(R.id.fresco_logo) 58 | ImageView imageView; 59 | @Bind(R.id.et_nickname) 60 | EditText met_nickname; 61 | @Bind(R.id.met_phone_userinfo) 62 | EditText met_phone; 63 | @Bind(R.id.et_mail) 64 | EditText met_mail; 65 | @Bind(R.id.et_rank) 66 | EditText met_rank; 67 | @Bind(R.id.lv_record) 68 | ListView lv_record; 69 | @Bind(R.id.btn_changePwd) 70 | ImageButton mbtn_changePwd; 71 | @Bind(R.id.btn_exitAccount) 72 | ImageButton mbtn_exit; 73 | @Bind(R.id.toolbar) 74 | Toolbar toolbar; 75 | 76 | 77 | private User user_login; //登陆者账号信息 78 | View inflate;//解析AlertDialog内部布局的view 79 | AlertDialog alertDialog; //更换头像时弹出的对话框 80 | List mRecordSet; 81 | RecordAdapter mAdapter; 82 | 83 | @Override 84 | protected void onCreate(Bundle savedInstanceState) { 85 | super.onCreate(savedInstanceState); 86 | setContentView(R.layout.activity_user_info); 87 | ButterKnife.bind(this); 88 | setSupportActionBar(toolbar); 89 | toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); 90 | 91 | initView();//实例化控件 92 | user_login = PuzzleApplication.getmUser(); 93 | setInfo();//为各个控件填充信息 94 | 95 | BmobQuery query = new BmobQuery(); 96 | query.setLimit(20); 97 | query.addWhereEqualTo("phoneNum", PuzzleApplication.getmUser().getPhoneNum()); 98 | query.findObjects(this, new FindListener() { 99 | @Override 100 | public void onSuccess(List list) { 101 | mRecordSet = list; 102 | mAdapter = new RecordAdapter(mRecordSet, UserInfoActivity.this); 103 | lv_record.setAdapter(mAdapter); 104 | } 105 | 106 | @Override 107 | public void onError(int i, String s) { 108 | Log.e("main", s); 109 | } 110 | }); 111 | 112 | AlertDialog.Builder builder = new AlertDialog.Builder(UserInfoActivity.this); 113 | inflate = UserInfoActivity.this.getLayoutInflater().inflate(R.layout.layout_alertdiag, null, false); 114 | builder.setView(inflate); 115 | builder.setTitle("自定义头像"); 116 | alertDialog = builder.create(); 117 | 118 | findViewById(R.id.fresco_logo).setOnClickListener(new View.OnClickListener() { 119 | @Override 120 | public void onClick(View v) { 121 | alertDialog.show(); 122 | } 123 | }); 124 | 125 | 126 | inflate.findViewById(R.id.btn_camera_changePic).setOnClickListener(new View.OnClickListener() { 127 | @Override 128 | public void onClick(View v) { 129 | alertDialog.dismiss(); 130 | setPicFromCamera(); 131 | } 132 | }); 133 | 134 | inflate.findViewById(R.id.btn_gallery_changePic).setOnClickListener(new View.OnClickListener() { 135 | @Override 136 | public void onClick(View v) { 137 | alertDialog.dismiss(); 138 | setPicFromGallery(); 139 | } 140 | }); 141 | 142 | 143 | } 144 | 145 | 146 | private void setPicFromGallery() { 147 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 148 | intent.setType("image/*"); 149 | startActivityForResult(intent, GALLERY_REQUEST_CODE); 150 | } 151 | 152 | private void setPicFromCamera() { 153 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 154 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 155 | startActivityForResult(intent, CAMERA_REQUEST_CODE); 156 | } 157 | 158 | private Bitmap decodeUriAsBitmap(Uri uri) { 159 | Bitmap bitmap = null; 160 | try { 161 | bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); 162 | } catch (FileNotFoundException e) { 163 | e.printStackTrace(); 164 | return null; 165 | } 166 | return bitmap; 167 | } 168 | 169 | private void cropImageUri(Uri uri, int outputX, int outputY, int requestCode) { 170 | Intent intent = new Intent("com.android.camera.action.CROP"); 171 | intent.setDataAndType(uri, "image/*"); 172 | intent.putExtra("crop", "true"); 173 | intent.putExtra("aspectX", 1); 174 | intent.putExtra("aspectY", 1); 175 | intent.putExtra("outputX", outputX); 176 | intent.putExtra("outputY", outputY); 177 | intent.putExtra("scale", true); 178 | intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); 179 | intent.putExtra("return-data", false); 180 | intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); 181 | intent.putExtra("noFaceDetection", true); // no face detection 182 | startActivityForResult(intent, requestCode); 183 | } 184 | 185 | private void setInfo() { 186 | met_phone.setText(PuzzleApplication.getmUser().getPhoneNum()); 187 | met_nickname.setText(PuzzleApplication.getmUser().getNickName()); 188 | met_mail.setText(PuzzleApplication.getmUser().getMailNum()); 189 | if (!user_login.getImgUrl().equals("null")) { 190 | 191 | new Thread(new Runnable() { 192 | @Override 193 | public void run() { 194 | String imageUrl = user_login.getImgUrl(); 195 | final Bitmap bitmap = returnBitMap(imageUrl); 196 | runOnUiThread(new Runnable() { 197 | @Override 198 | public void run() { 199 | imageView.setImageBitmap(bitmap); 200 | } 201 | }); 202 | 203 | } 204 | }).start(); 205 | } 206 | } 207 | 208 | public Bitmap returnBitMap(String url) { 209 | 210 | URL myFileUrl = null; 211 | Bitmap bitmap = null; 212 | try { 213 | myFileUrl = new URL(url); 214 | } catch (MalformedURLException e) { 215 | e.printStackTrace(); 216 | } 217 | try { 218 | HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection(); 219 | conn.setDoInput(true); 220 | conn.connect(); 221 | InputStream is = conn.getInputStream(); 222 | bitmap = BitmapFactory.decodeStream(is); 223 | is.close(); 224 | } catch (IOException e) { 225 | e.printStackTrace(); 226 | } 227 | return bitmap; 228 | } 229 | 230 | 231 | private void initView() { 232 | met_mail.setEnabled(false); 233 | met_rank.setEnabled(false); 234 | met_phone.setEnabled(false); 235 | met_nickname.setEnabled(false); 236 | met_rank.setText("第一名"); 237 | } 238 | 239 | 240 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 241 | 242 | if (requestCode == CAMERA_REQUEST_CODE) { 243 | cropImageUri(imageUri, 300, 300, CROP_REQUEST_CODE); 244 | } else if (requestCode == GALLERY_REQUEST_CODE) { 245 | 246 | if (data == null) { 247 | return; 248 | } 249 | Uri uri = data.getData();//content类型的uri 250 | Intent intent = new Intent("com.android.camera.action.CROP"); 251 | intent.setDataAndType(uri, "image/*"); 252 | intent.putExtra("crop", "true"); 253 | intent.putExtra("aspectX", 1); 254 | intent.putExtra("aspectY", 1); 255 | intent.putExtra("outputX", 300); 256 | intent.putExtra("outputY", 300); 257 | intent.putExtra("return-data", false); 258 | intent.putExtra("scale", true); 259 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 260 | intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); 261 | intent.putExtra("noFaceDetection", true); // no face detection 262 | startActivityForResult(intent, CROP_REQUEST_CODE); 263 | 264 | } else if (requestCode == CROP_REQUEST_CODE) { 265 | 266 | if (imageUri != null) { 267 | Bitmap bitmap = decodeUriAsBitmap(imageUri);//decode bitmap 268 | imageView.setImageBitmap(bitmap); 269 | File tempDir = new File(Environment.getExternalStorageDirectory() + ""); 270 | String picPath = tempDir.getAbsolutePath() + "/temp.jpg"; 271 | final BmobFile bmobFile = new BmobFile(new File(picPath)); 272 | 273 | bmobFile.uploadblock(UserInfoActivity.this, new UploadFileListener() { 274 | @Override 275 | public void onSuccess() { 276 | 277 | user_login.setImgUrl(bmobFile.getFileUrl(UserInfoActivity.this)); 278 | String obId = user_login.getObjectId(); 279 | user_login.update(UserInfoActivity.this, obId, new UpdateListener() { 280 | @Override 281 | public void onSuccess() { 282 | Log.i("main", "更新头像URL成功"); 283 | } 284 | 285 | @Override 286 | public void onFailure(int i, String s) { 287 | Log.e("main", s); 288 | 289 | } 290 | }); 291 | } 292 | 293 | @Override 294 | public void onProgress(Integer value) { 295 | // 返回的上传进度(百分比) 296 | } 297 | 298 | @Override 299 | public void onFailure(int code, String msg) { 300 | Log.e("main", msg); 301 | } 302 | }); 303 | 304 | } 305 | 306 | 307 | } else if (requestCode == 1234) { 308 | if (data == null) { 309 | 310 | } else { 311 | User mReUser = (User) data.getSerializableExtra("reuser"); 312 | user_login = mReUser; 313 | PuzzleApplication.setmUser(mReUser); 314 | } 315 | 316 | } 317 | 318 | } 319 | 320 | 321 | @Override 322 | public boolean onCreateOptionsMenu(Menu menu) { 323 | getMenuInflater().inflate(R.menu.menu_user_info, menu); 324 | return true; 325 | } 326 | 327 | @Override 328 | public boolean onOptionsItemSelected(MenuItem item) { 329 | int id = item.getItemId(); 330 | 331 | if (id == R.id.menuItem_edit) { 332 | CharSequence title = item.getTitle(); 333 | if (item.getTitle().equals("编辑")) { 334 | item.setTitle("保存"); 335 | met_nickname.setEnabled(true); 336 | met_mail.setEnabled(true); 337 | 338 | } else { 339 | item.setTitle("编辑"); 340 | met_nickname.setEnabled(false); 341 | met_mail.setEnabled(false); 342 | if (!(user_login.getMailNum().equals(met_mail.getText().toString()) && user_login.getNickName().equals(met_nickname.getText().toString()))) { 343 | user_login.setNickName(met_nickname.getText().toString()); 344 | user_login.setMailNum(met_mail.getText().toString()); 345 | user_login.update(UserInfoActivity.this, user_login.getObjectId(), new UpdateListener() { 346 | @Override 347 | public void onSuccess() { 348 | } 349 | 350 | @Override 351 | public void onFailure(int i, String s) { 352 | } 353 | }); 354 | } 355 | } 356 | return true; 357 | } else if (item.getItemId() == android.R.id.home) { 358 | finish(); 359 | return true; 360 | } 361 | 362 | return super.onOptionsItemSelected(item); 363 | } 364 | 365 | @OnClick({R.id.btn_changePwd, R.id.btn_exitAccount}) 366 | public void onClick(View view) { 367 | switch (view.getId()) { 368 | case R.id.btn_changePwd: 369 | ChangePwdActivity.actionStart(UserInfoActivity.this); 370 | break; 371 | case R.id.btn_exitAccount: 372 | LoginActivity.actionStart(UserInfoActivity.this); 373 | finish(); 374 | break; 375 | } 376 | } 377 | 378 | class RecordAdapter extends BaseAdapter { 379 | 380 | List mSet; 381 | Context mContext; 382 | 383 | public RecordAdapter(List mSet, Context mContext) { 384 | this.mSet = mSet; 385 | this.mContext = mContext; 386 | } 387 | 388 | @Override 389 | public int getCount() { 390 | return mSet.size(); 391 | } 392 | 393 | @Override 394 | public Record getItem(int position) { 395 | return mSet.get(position); 396 | } 397 | 398 | @Override 399 | public long getItemId(int position) { 400 | return position; 401 | } 402 | 403 | @Override 404 | public View getView(int position, View convertView, ViewGroup parent) { 405 | ViewHolder viewHolder = null; 406 | if (convertView == null) { 407 | convertView = View.inflate(mContext, R.layout.layout_record, null); 408 | viewHolder = new ViewHolder(); 409 | viewHolder.mtv_type = (TextView) convertView.findViewById(R.id.tv_lv_record_type); 410 | viewHolder.mtv_time = (TextView) convertView.findViewById(R.id.tv_lv_record_time); 411 | convertView.setTag(viewHolder); 412 | } else { 413 | viewHolder = (ViewHolder) convertView.getTag(); 414 | } 415 | 416 | viewHolder.mtv_time.setText(getItem(position).getTime()); 417 | viewHolder.mtv_type.setText(getItem(position).getType() + " x " + getItem(position).getType()); 418 | if (position % 2 == 0) { 419 | convertView.findViewById(R.id.linearlayout_record).setBackgroundColor(getResources().getColor(R.color.personGreyDark)); 420 | } 421 | return convertView; 422 | } 423 | 424 | 425 | class ViewHolder { 426 | TextView mtv_type; 427 | TextView mtv_time; 428 | } 429 | } 430 | 431 | public static void actionStart(Context context) { 432 | Intent intent = new Intent(context, UserInfoActivity.class); 433 | context.startActivity(intent); 434 | } 435 | 436 | } 437 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/adapter/ChoosePicGridViewAdapter.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.ImageView; 9 | 10 | import studio.androiddev.puzzle.R; 11 | import studio.androiddev.puzzle.activity.ChoosePicActivity; 12 | import studio.androiddev.puzzle.utils.BitmapUtils; 13 | 14 | /** 15 | * puzzle 16 | * Created by ZQ on 2016/4/24. 17 | */ 18 | public class ChoosePicGridViewAdapter extends ArrayAdapter { 19 | 20 | int resourceId; 21 | 22 | public ChoosePicGridViewAdapter(Context context, int resourceId){ 23 | super(context, resourceId); 24 | this.resourceId = resourceId; 25 | } 26 | 27 | @Override 28 | public int getCount(){ 29 | return ChoosePicActivity.icons.length; 30 | } 31 | 32 | @Override 33 | public View getView(int position, View convertView, ViewGroup parent){ 34 | ViewHolder holder = null; 35 | View view; 36 | if(convertView == null){ 37 | view = LayoutInflater.from(getContext()).inflate(resourceId, null); 38 | holder = new ViewHolder(); 39 | holder.imageView = (ImageView) view.findViewById(R.id.imageItem); 40 | view.setTag(holder); 41 | }else{ 42 | view = convertView; 43 | holder = (ViewHolder) view.getTag(); 44 | } 45 | 46 | holder.imageView.setImageBitmap(BitmapUtils.decodeSampledBitmapFromResources( 47 | getContext().getResources(), 48 | ChoosePicActivity.icons[position], 49 | 300, 50 | 300 51 | )); 52 | 53 | return view; 54 | } 55 | 56 | class ViewHolder{ 57 | ImageView imageView; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/bgm/MusicServer.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.bgm; 2 | 3 | /** 4 | * Created by Administrator on 2016/3/29. 5 | */ 6 | 7 | import android.app.Service; 8 | import android.content.Intent; 9 | import android.media.MediaPlayer; 10 | import android.os.IBinder; 11 | 12 | import java.io.IOException; 13 | 14 | import studio.androiddev.puzzle.R; 15 | 16 | public class MusicServer extends Service { 17 | 18 | private MediaPlayer mediaPlayer; 19 | private int songList[]={R.raw.a, R.raw.b, R.raw.c,R.raw.d}; 20 | private int songIndex = 0; 21 | @Override 22 | public IBinder onBind(Intent intent) { 23 | 24 | return null; 25 | } 26 | 27 | @Override 28 | public void onCreate() { 29 | super.onCreate(); 30 | } 31 | @Override 32 | public int onStartCommand(Intent intent, int flags, int startId){ 33 | 34 | if(mediaPlayer==null){ 35 | // R.raw.mmp是资源文件,MP3格式的 36 | try { 37 | nextsong(); 38 | mediaPlayer.setOnCompletionListener(new CompletionListener()); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | 43 | } 44 | 45 | return super.onStartCommand(intent, flags, startId); 46 | } 47 | 48 | private final class CompletionListener implements MediaPlayer.OnCompletionListener { 49 | 50 | @Override 51 | public void onCompletion(MediaPlayer mp) { 52 | try { 53 | nextsong(); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | } 60 | public void nextsong() throws IOException { 61 | songIndex = 0 + (int)(Math.random() * 4); 62 | songplay(); 63 | } 64 | private void songplay() throws IOException { 65 | try { 66 | if(mediaPlayer!=null) 67 | mediaPlayer.release(); 68 | mediaPlayer=MediaPlayer.create(this, songList[songIndex]); 69 | mediaPlayer.start(); 70 | } catch (IllegalArgumentException e) { 71 | e.printStackTrace(); 72 | } catch (SecurityException e) { 73 | e.printStackTrace(); 74 | } catch (IllegalStateException e) { 75 | e.printStackTrace(); 76 | } 77 | 78 | } 79 | 80 | 81 | @Override 82 | public void onDestroy() { 83 | super.onDestroy(); 84 | mediaPlayer.stop(); 85 | mediaPlayer = null; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/db/DBHelper.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.db; 2 | 3 | /** 4 | * Puzzle 5 | * Created by ZQ on 2016/3/24. 6 | */ 7 | public class DBHelper { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/dish/DishManager.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.dish; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.PorterDuff; 8 | import android.graphics.PorterDuffXfermode; 9 | import android.graphics.RectF; 10 | import android.util.Log; 11 | import android.view.DragEvent; 12 | import android.view.View; 13 | import android.widget.ImageView; 14 | 15 | import org.greenrobot.eventbus.EventBus; 16 | 17 | import studio.androiddev.puzzle.PuzzleApplication; 18 | import studio.androiddev.puzzle.event.GameSuccessEvent; 19 | import studio.androiddev.puzzle.event.PieceMoveSuccessEvent; 20 | import studio.androiddev.puzzle.utils.DensityUtil; 21 | 22 | /** 23 | * puzzle 24 | * 拼盘管理类,用于更新拼盘的显示 25 | * Created by ZQ on 2016/4/3. 26 | */ 27 | public class DishManager{ 28 | 29 | private static final String TAG = "puzzle"; 30 | 31 | //拼盘 32 | private ImageView mImageView; 33 | //游戏难度 34 | private int mLevel; 35 | //拼图图片 36 | private Bitmap mBitmap; 37 | //拼图数组 38 | private boolean[] mIndex; 39 | //拼块数目 40 | private int mSize; 41 | //距离游戏胜利还需移动的拼块数目 42 | private int mLeftSize; 43 | //拼盘大小 44 | private static int DISH_HEIGHT = 300; 45 | private static int DISH_WIDTH = 300; 46 | 47 | //基本款遮罩拼块 48 | //private static Bitmap[] bmcover = new Bitmap[9]; 49 | public static final int COVER_CENTER = 0; 50 | public static final int COVER_TOP = 1; 51 | public static final int COVER_BOTTOM = 2; 52 | public static final int COVER_LEFT = 3; 53 | public static final int COVER_RIGHT = 4; 54 | public static final int COVER_TOP_LEFT = 5; 55 | public static final int COVER_TOP_RIGHT = 6; 56 | public static final int COVER_BOTTOM_LEFT = 7; 57 | public static final int COVER_BOTTOM_RIGHT = 8; 58 | //拼块凹凸半径 59 | private static float r; 60 | //拼块内的矩形长宽 61 | private static float rectWidth; 62 | private static float rectHeight; 63 | //拼块的长宽 64 | static float width; 65 | static float height; 66 | 67 | public DishManager(int level){ 68 | mLevel = level; 69 | mSize = level * level; 70 | mLeftSize = mSize; 71 | mIndex = new boolean[mSize]; 72 | for(int i = 0; i < mSize; i++) mIndex[i] = false; 73 | 74 | p = new Paint(); 75 | p.setColor(Color.RED); 76 | 77 | pOut = new Paint(); 78 | pOut.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 79 | pOut.setAntiAlias(true); 80 | pOut.setColor(Color.RED); 81 | 82 | pOver = new Paint(); 83 | pOver.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); 84 | pOver.setAntiAlias(true); 85 | pOver.setColor(Color.RED); 86 | 87 | initMask(); 88 | } 89 | 90 | /** 91 | * 游戏结束后调用,释放资源 92 | */ 93 | public void recycle(){ 94 | if(mImageView != null) { 95 | mImageView = null; 96 | } 97 | if(mBitmap != null && !mBitmap.isRecycled()){ 98 | mBitmap.recycle(); 99 | } 100 | 101 | } 102 | 103 | /** 104 | * 初始化新游戏 105 | * @param bitmap 新游戏图片 106 | * @param imageView 新游戏的拼盘 107 | */ 108 | public void initNewGame(Bitmap bitmap, ImageView imageView){ 109 | if(bitmap == null || imageView == null) return; 110 | 111 | if(mBitmap != null && !mBitmap.isRecycled()){ 112 | mBitmap.recycle(); 113 | } 114 | 115 | mImageView = imageView; 116 | mBitmap = bitmap; 117 | mLeftSize = mSize; 118 | for(int i = 0; i < mIndex.length; i++){ 119 | mIndex[i] = false; 120 | } 121 | 122 | imageView.setOnDragListener(new View.OnDragListener() { 123 | @Override 124 | public boolean onDrag(View v, DragEvent event) { 125 | int x = (int) event.getX(); 126 | int y = (int) event.getY(); 127 | int index = (int) event.getLocalState(); 128 | 129 | switch (event.getAction()){ 130 | case DragEvent.ACTION_DRAG_STARTED: 131 | 132 | break; 133 | case DragEvent.ACTION_DRAG_ENTERED: 134 | 135 | break; 136 | case DragEvent.ACTION_DRAG_EXITED: 137 | 138 | break; 139 | case DragEvent.ACTION_DRAG_ENDED: 140 | 141 | break; 142 | case DragEvent.ACTION_DROP: 143 | 144 | if(judgeDrag(index, x, y)){ 145 | updatePiece(index); 146 | } 147 | 148 | break; 149 | default: 150 | break; 151 | } 152 | 153 | return true; 154 | } 155 | }); 156 | 157 | refreshDish(); 158 | } 159 | 160 | public void setBitmap(Bitmap bitmap){ 161 | mBitmap = bitmap; 162 | } 163 | 164 | public void setLevel(int level){ 165 | mLevel = level; 166 | } 167 | 168 | // public static Bitmap[] getBitmapCover() { 169 | // return bmcover; 170 | // } 171 | 172 | public static Bitmap getCover(int index){ 173 | Bitmap bitmap = Bitmap.createBitmap( 174 | (int) width, 175 | (int) height, 176 | Bitmap.Config.ARGB_8888); 177 | 178 | Canvas canvas = new Canvas(bitmap); 179 | 180 | switch (index){ 181 | case COVER_TOP_LEFT: 182 | canvas.drawRect(0, 0, rectWidth, rectHeight, p); 183 | canvas.drawArc(ovalRight, 0, 360, true, pOut); 184 | canvas.drawArc(ovalBottom, 0, 360, true, pOver); 185 | break; 186 | case COVER_TOP: 187 | canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 188 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 189 | canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 190 | canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 191 | break; 192 | case COVER_TOP_RIGHT: 193 | canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 194 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 195 | canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 196 | break; 197 | case COVER_LEFT: 198 | canvas.drawRect(0, 0, rectWidth, rectHeight, p); 199 | canvas.drawArc(ovalBottom, 0, 360, true, pOver); 200 | canvas.drawArc(ovalTop, 0, 360, true, pOut); 201 | canvas.drawArc(ovalRight, 0, 360, true, pOut); 202 | break; 203 | case COVER_CENTER: 204 | canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 205 | canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 206 | canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 207 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 208 | canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 209 | break; 210 | case COVER_BOTTOM_LEFT: 211 | canvas.drawRect(0, 0, rectWidth, rectHeight, p); 212 | canvas.drawArc(ovalTop, 0, 360, true, pOut); 213 | canvas.drawArc(ovalRight, 0, 360, true, pOut); 214 | break; 215 | case COVER_BOTTOM: 216 | canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 217 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 218 | canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 219 | canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 220 | break; 221 | case COVER_BOTTOM_RIGHT: 222 | canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 223 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 224 | canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 225 | break; 226 | case COVER_RIGHT: 227 | canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 228 | canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 229 | canvas.drawArc(ovalLeft, 0, 360, true, pOver); 230 | canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 231 | } 232 | 233 | canvas.save(); 234 | return bitmap; 235 | } 236 | 237 | /** 238 | * 判断拼块是否被拖动到正确的位置 239 | * @param i 拼块下标 240 | * @param x 拖动事件x坐标 241 | * @param y 拖动事件y坐标 242 | * @return 判断结果 243 | */ 244 | public boolean judgeDrag(int i, int x, int y){ 245 | RectF rect = getRectF(i); 246 | return rect.contains(x, y); 247 | } 248 | 249 | /** 250 | * 根据拼块下标计算拼块实际占据的方形大小 251 | * @param i 拼块下标 252 | * @return 拼块实际占据的方形大小 253 | */ 254 | private RectF getRectF(int i){ 255 | 256 | return new RectF( 257 | (i % mLevel) * rectWidth, 258 | (i / mLevel) * rectHeight, 259 | (i % mLevel + 1) * rectWidth, 260 | (i / mLevel + 1) * rectHeight); 261 | } 262 | 263 | /** 264 | * 当玩家将拼块移动到正确位置时调用,更新拼盘显示状态 265 | * @param i 正确的拼块下标 266 | */ 267 | public void updatePiece(int i){ 268 | if(i < 0 || i > mLevel * mLevel) return; 269 | 270 | mIndex[i] = true; 271 | refreshDish(); 272 | EventBus.getDefault().post(new PieceMoveSuccessEvent(i)); 273 | mLeftSize--; 274 | if(mLeftSize == 0){ 275 | EventBus.getDefault().post(new GameSuccessEvent()); 276 | } 277 | } 278 | 279 | /** 280 | * 根据拼盘大小和游戏难度初始化基本遮罩拼块 281 | */ 282 | private void initMask(){ 283 | 284 | rectWidth = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_WIDTH / mLevel); 285 | rectHeight = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_HEIGHT / mLevel); 286 | r = rectWidth / 4; 287 | 288 | Log.d(TAG, "rectWidth and Height: " + rectWidth); 289 | 290 | width = rectWidth + r; 291 | height = rectHeight + r; 292 | 293 | ovalLeft = new RectF(0, rectHeight / 2 - r, 2 * r, rectHeight / 2 + r); 294 | ovalTop = new RectF(rectWidth / 2 - r, - r, rectWidth / 2 + r, r); 295 | ovalTopRight = new RectF(rectWidth / 2, - r, rectWidth / 2 + 2 * r, r); 296 | ovalRight = new RectF(rectWidth - r, rectHeight / 2 - r, rectWidth + r, rectHeight / 2 + r); 297 | ovalBottom = new RectF(rectWidth / 2 - r, rectHeight - r, rectWidth / 2 + r, rectHeight + r); 298 | ovalRightRight = new RectF(rectWidth, rectHeight / 2 - r, rectWidth + 2 * r, rectHeight / 2 + r); 299 | ovalBottomRight = new RectF(rectWidth / 2, rectHeight - r, rectWidth / 2 + 2 * r, rectHeight + r); 300 | 301 | // for(int i = 0; i < 9; i++){ 302 | // if(bmcover[i] != null){ 303 | // bmcover[i].recycle(); 304 | // bmcover[i] = null; 305 | // } 306 | // System.gc(); 307 | // } 308 | 309 | // for(int i = 0; i < 9; i++){ 310 | // bmcover[i] = Bitmap.createBitmap( 311 | // (int) width, 312 | // (int) height, 313 | // Bitmap.Config.ARGB_8888); 314 | // } 315 | // 316 | // Paint p = new Paint(); 317 | // p.setColor(Color.RED); 318 | // 319 | // Paint pOut = new Paint(); 320 | // pOut.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 321 | // pOut.setAntiAlias(true); 322 | // pOut.setColor(Color.RED); 323 | // 324 | // Paint pOver = new Paint(); 325 | // pOver.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); 326 | // pOver.setAntiAlias(true); 327 | // pOver.setColor(Color.RED); 328 | // 329 | // RectF ovalLeft = new RectF(0, rectHeight / 2 - r, 2 * r, rectHeight / 2 + r); 330 | // RectF ovalTop = new RectF(rectWidth / 2 - r, - r, rectWidth / 2 + r, r); 331 | // RectF ovalTopRight = new RectF(rectWidth / 2, - r, rectWidth / 2 + 2 * r, r); 332 | // RectF ovalRight = new RectF(rectWidth - r, rectHeight / 2 - r, rectWidth + r, rectHeight / 2 + r); 333 | // RectF ovalBottom = new RectF(rectWidth / 2 - r, rectHeight - r, rectWidth / 2 + r, rectHeight + r); 334 | // RectF ovalRightRight = new RectF(rectWidth, rectHeight / 2 - r, rectWidth + 2 * r, rectHeight / 2 + r); 335 | // RectF ovalBottomRight = new RectF(rectWidth / 2, rectHeight - r, rectWidth / 2 + 2 * r, rectHeight + r); 336 | // 337 | // Canvas canvas = new Canvas(bmcover[COVER_TOP_LEFT]); 338 | // canvas.drawRect(0, 0, rectWidth, rectHeight, p); 339 | // canvas.drawArc(ovalRight, 0, 360, true, pOut); 340 | // canvas.drawArc(ovalBottom, 0, 360, true, pOver); 341 | // canvas.save(); 342 | // 343 | // canvas.setBitmap(bmcover[COVER_TOP]); 344 | // canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 345 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 346 | // canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 347 | // canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 348 | // canvas.save(); 349 | // 350 | // canvas.setBitmap(bmcover[COVER_TOP_RIGHT]); 351 | // canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 352 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 353 | // canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 354 | // canvas.save(); 355 | // 356 | // canvas.setBitmap(bmcover[COVER_LEFT]); 357 | // canvas.drawRect(0, 0, rectWidth, rectHeight, p); 358 | // canvas.drawArc(ovalBottom, 0, 360, true, pOver); 359 | // canvas.drawArc(ovalTop, 0, 360, true, pOut); 360 | // canvas.drawArc(ovalRight, 0, 360, true, pOut); 361 | // canvas.save(); 362 | // 363 | // canvas.setBitmap(bmcover[COVER_CENTER]); 364 | // canvas.drawRect(r, 0, r + rectWidth, rectHeight, p); 365 | // canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 366 | // canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 367 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 368 | // canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 369 | // canvas.save(); 370 | // 371 | // canvas.setBitmap(bmcover[COVER_BOTTOM_LEFT]); 372 | // canvas.drawRect(0, 0, rectWidth, rectHeight, p); 373 | // canvas.drawArc(ovalTop, 0, 360, true, pOut); 374 | // canvas.drawArc(ovalRight, 0, 360, true, pOut); 375 | // canvas.save(); 376 | // 377 | // canvas.setBitmap(bmcover[COVER_BOTTOM]); 378 | // canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 379 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 380 | // canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 381 | // canvas.drawArc(ovalRightRight, 0, 360, true, pOut); 382 | // canvas.save(); 383 | // 384 | // canvas.setBitmap(bmcover[COVER_BOTTOM_RIGHT]); 385 | // canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 386 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 387 | // canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 388 | // canvas.save(); 389 | // 390 | // canvas.setBitmap(bmcover[COVER_RIGHT]); 391 | // canvas.drawRect(r, 0, rectWidth + r, rectHeight, p); 392 | // canvas.drawArc(ovalTopRight, 0, 360, true, pOut); 393 | // canvas.drawArc(ovalLeft, 0, 360, true, pOver); 394 | // canvas.drawArc(ovalBottomRight, 0, 360, true, pOver); 395 | // canvas.save(); 396 | 397 | } 398 | private static Paint p, pOut, pOver; 399 | private static RectF ovalLeft, ovalTop, ovalTopRight, ovalRight, ovalBottom, ovalRightRight, ovalBottomRight; 400 | 401 | /** 402 | * 根据当前游戏进度生成遮罩层 403 | * @return 遮罩层Bitmap 404 | */ 405 | private Bitmap getMask(){ 406 | int width = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_WIDTH); 407 | int height = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_HEIGHT); 408 | Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 409 | Canvas canvas = new Canvas(mask); 410 | 411 | Paint p = new Paint(); 412 | p.setAntiAlias(true); 413 | p.setColor(Color.RED); 414 | 415 | for(int i = 0; i < mSize; i += mLevel){ 416 | for(int j = i; j < i + mLevel; j++){ 417 | if(!mIndex[j]) continue; 418 | 419 | Bitmap cover; 420 | 421 | //最右一列 422 | if((j + 1) % mLevel == 0) { 423 | //右上角 424 | if(j == mLevel - 1) { 425 | cover = getCover(COVER_TOP_RIGHT); 426 | canvas.drawBitmap(cover, rectWidth * (mLevel - 1) - r, 0, p); 427 | } 428 | //右下角 429 | else if (j == mSize - 1){ 430 | cover = getCover(COVER_BOTTOM_RIGHT); 431 | canvas.drawBitmap( 432 | cover, 433 | rectWidth * (mLevel - 1) - r, 434 | rectHeight * (mLevel - 1), p); 435 | } 436 | else{ 437 | cover = getCover(COVER_RIGHT); 438 | canvas.drawBitmap(cover, 439 | rectWidth * (mLevel - 1) - r, 440 | rectHeight * (i / mLevel), p); 441 | } 442 | 443 | } 444 | //最左一列 445 | else if(j % mLevel == 0) { 446 | //左上角 447 | if(j == 0){ 448 | cover = getCover(COVER_TOP_LEFT); 449 | canvas.drawBitmap(cover, 0, 0, p); 450 | } 451 | //左下角 452 | if(j == mSize - mLevel + 1){ 453 | cover = getCover(COVER_BOTTOM_LEFT); 454 | canvas.drawBitmap(cover, 455 | 0, 456 | rectHeight * (mLevel - 1), p); 457 | } 458 | 459 | else{ 460 | cover = getCover(COVER_LEFT); 461 | canvas.drawBitmap(cover, 462 | 0, 463 | rectHeight * (i / mLevel), p); 464 | } 465 | } 466 | //最上一行 467 | else if(j < mLevel){ 468 | cover = getCover(COVER_TOP); 469 | canvas.drawBitmap(cover, 470 | rectWidth * j - r, 471 | 0, p); 472 | } 473 | //最下一行 474 | else if(j > (mSize - mLevel)){ 475 | cover = getCover(COVER_BOTTOM); 476 | canvas.drawBitmap(cover, 477 | rectWidth * (j % mLevel) - r, 478 | rectHeight * (mLevel - 1), p); 479 | } 480 | //中间 481 | else{ 482 | cover = getCover(COVER_CENTER); 483 | canvas.drawBitmap(cover, 484 | rectWidth * (j % mLevel) - r, 485 | rectHeight * (i / mLevel), p); 486 | } 487 | 488 | cover.recycle(); 489 | 490 | } 491 | 492 | } 493 | 494 | canvas.save(); 495 | 496 | return mask; 497 | } 498 | 499 | private Bitmap output; 500 | private Bitmap mask; 501 | /** 502 | * 刷新拼盘显示 503 | * 首先获取遮罩层,然后将遮罩层与原始图片混合并显示 504 | */ 505 | private void refreshDish(){ 506 | if(mBitmap == null) return; 507 | if(mask != null) mask.recycle(); 508 | if(output != null) output.recycle(); 509 | //获取遮罩层 510 | mask = getMask(); 511 | 512 | //将遮罩层与原始图片混合并显示在ImageView 513 | int width = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_WIDTH); 514 | int height = DensityUtil.dip2px(PuzzleApplication.getAppContext(), (float) DISH_HEIGHT); 515 | output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 516 | Paint p = new Paint(); 517 | 518 | p.setAntiAlias(true); 519 | Canvas canvas = new Canvas(output); 520 | canvas.drawBitmap(mask, 0, 0, p); 521 | p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 522 | RectF rect = new RectF(0, 0, width, height); 523 | canvas.drawBitmap(mBitmap, null, rect, p); 524 | mImageView.setImageBitmap(output); 525 | } 526 | 527 | } 528 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/dish/DragImageView.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.dish; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * puzzle 10 | * Created by ZQ on 2016/4/4. 11 | */ 12 | public class DragImageView extends ImageView { 13 | 14 | private int mIndex; 15 | 16 | public DragImageView(Context context) { 17 | super(context); 18 | init(context); 19 | } 20 | 21 | public DragImageView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(context); 24 | } 25 | 26 | public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | init(context); 29 | } 30 | 31 | private void init(Context context) { 32 | 33 | setOnLongClickListener(new OnLongClickListener() { 34 | @Override 35 | public boolean onLongClick(View v) { 36 | v.startDrag(null, new View.DragShadowBuilder(v), mIndex, 0); 37 | return true; 38 | } 39 | }); 40 | } 41 | 42 | public void setIndex(int index) { 43 | mIndex = index; 44 | } 45 | 46 | public int getIndex(){ 47 | return mIndex; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/event/DishManagerInitFinishEvent.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.event; 2 | 3 | /** 4 | * puzzle 5 | * Created by ZQ on 2016/4/19. 6 | */ 7 | public class DishManagerInitFinishEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/event/DishManagerInitStartEvent.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.event; 2 | 3 | /** 4 | * puzzle 5 | * Created by ZQ on 2016/4/19. 6 | */ 7 | public class DishManagerInitStartEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/event/GameSuccessEvent.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.event; 2 | 3 | /** 4 | * puzzle 5 | * Created by ZQ on 2016/4/17. 6 | */ 7 | public class GameSuccessEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/event/PieceMoveSuccessEvent.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.event; 2 | 3 | /** 4 | * puzzle 5 | * Created by ZQ on 2016/4/17. 6 | */ 7 | public class PieceMoveSuccessEvent { 8 | 9 | private int index; 10 | public PieceMoveSuccessEvent(int index){ 11 | this.index = index; 12 | } 13 | 14 | public int getIndex(){ 15 | return index; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/event/TimeEvent.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.event; 2 | 3 | /** 4 | * puzzle 5 | * Created by ZQ on 2016/4/27. 6 | */ 7 | public class TimeEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/imagesplit/ImagePiece.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.imagesplit; 2 | 3 | /** 4 | * Created by Administrator on 2016/3/27. 5 | */ 6 | import android.graphics.Bitmap; 7 | 8 | public class ImagePiece { 9 | 10 | public int index = 0; 11 | 12 | public Bitmap bitmap = null; 13 | 14 | public void recycleBitmap(){ 15 | if(bitmap != null){ 16 | bitmap.recycle(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/imagesplit/ImageSplitter.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.imagesplit; 2 | 3 | /** 4 | * Created by Administrator on 2016/3/27. 5 | */ 6 | 7 | import android.graphics.Bitmap; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.graphics.Paint; 11 | import android.graphics.PorterDuff; 12 | import android.graphics.PorterDuffXfermode; 13 | import android.util.Log; 14 | 15 | import java.io.FileNotFoundException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | import studio.androiddev.puzzle.dish.DishManager; 20 | 21 | public class ImageSplitter { 22 | 23 | private static final String TAG = "puzzle"; 24 | 25 | public static List split(Bitmap bitmap, int level, int dishWidth, int dishHeight) 26 | throws FileNotFoundException { 27 | // Bitmap[] bmcover = DishManager.getBitmapCover(); 28 | List pieces = new ArrayList<>(level * level); 29 | 30 | float pieceWidth = (float) dishWidth / level; 31 | float pieceHeight = (float) dishHeight / level; 32 | PorterDuffXfermode pdf = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 33 | Log.d(TAG, "pieceWidth: " + pieceWidth); 34 | 35 | int k; 36 | Log.d(TAG, "circle begin"); 37 | for (int i = 0; i < level; i++) { 38 | for (int j = 0; j < level; j++) { 39 | if(i == 0) { 40 | if (j == 0) { 41 | k = DishManager.COVER_TOP_LEFT; 42 | } else if(j == level - 1) { 43 | k = DishManager.COVER_TOP_RIGHT; 44 | } 45 | else { 46 | k = DishManager.COVER_TOP; 47 | } 48 | } 49 | else if(i == level - 1) { 50 | if(j == 0) { 51 | k = DishManager.COVER_BOTTOM_LEFT; 52 | } else if (j == level - 1) { 53 | k = DishManager.COVER_BOTTOM_RIGHT; 54 | } else{ 55 | k = DishManager.COVER_BOTTOM; 56 | } 57 | } 58 | else if(j == 0) { 59 | k = DishManager.COVER_LEFT; 60 | }else if(j == level - 1) { 61 | k = DishManager.COVER_RIGHT; 62 | }else { 63 | k = DishManager.COVER_CENTER; 64 | } 65 | 66 | Log.d(TAG, "piece " + k + " compute completed"); 67 | 68 | ImagePiece piece = new ImagePiece(); 69 | piece.index = j + i * level; 70 | float xValue, yValue; 71 | 72 | if(j != 0) { 73 | //xValue = (int) (j * (pieceWidth - pieceWidth * 0.25)); 74 | xValue = (int) (j * pieceWidth - pieceWidth * 0.25); 75 | } 76 | else { 77 | xValue = j * pieceWidth; 78 | } 79 | if(i != 0) { 80 | //yValue = (int) (i * (pieceHeight - pieceWidth * 0.25)); 81 | yValue = i * pieceHeight; 82 | if(i != level - 1){ 83 | yValue += 0.25f * pieceHeight; 84 | } 85 | } 86 | else { 87 | yValue = i * pieceHeight; 88 | } 89 | 90 | // xValue = j * pieceWidth; 91 | // yValue = i * pieceHeight; 92 | 93 | Bitmap drawingBitmap = Bitmap.createBitmap((int) pieceWidth, 94 | (int) pieceHeight, Bitmap.Config.ARGB_8888); 95 | Canvas canvas = new Canvas(drawingBitmap); 96 | Paint paint = new Paint(); 97 | 98 | //final float scale = DensityUtil.getScale(PuzzleApplication.getAppContext()); 99 | Bitmap cover = DishManager.getCover(k); 100 | final float scale = pieceWidth / cover.getWidth(); 101 | Matrix matrix = new Matrix(); 102 | matrix.setScale(scale, scale); 103 | canvas.drawBitmap(cover, matrix, paint); 104 | cover.recycle(); 105 | // canvas.drawBitmap(bmcover[k], 0, 0, paint); 106 | 107 | float width = pieceWidth; 108 | float height = pieceHeight; 109 | if(i != level - 1){ 110 | height += pieceHeight * 0.25f; 111 | } 112 | if(j != 0){ 113 | width += pieceWidth * 0.25f; 114 | } 115 | 116 | paint.setXfermode(pdf); 117 | piece.bitmap = Bitmap.createBitmap( 118 | bitmap, 119 | (int) xValue, (int) yValue, 120 | (int) width, (int) height); 121 | 122 | canvas.drawBitmap(piece.bitmap, 0, 0, paint); 123 | piece.bitmap.recycle(); 124 | piece.bitmap = drawingBitmap; 125 | pieces.add(piece); 126 | Log.d(TAG, "piece " + k + " draw completed"); 127 | } 128 | } 129 | System.gc(); 130 | 131 | return pieces; 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/imagesplit/Uri2FilePath.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.imagesplit; 2 | 3 | import android.app.Activity; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | import android.provider.DocumentsContract; 7 | import android.provider.MediaStore; 8 | 9 | public class Uri2FilePath { 10 | public String path=null; 11 | public Uri2FilePath(Uri uri, Activity activity) { 12 | 13 | String path = ""; 14 | 15 | if (DocumentsContract.isDocumentUri(activity, uri)) { 16 | 17 | String wholeID = DocumentsContract.getDocumentId(uri); 18 | 19 | String id = wholeID.split(":")[1]; 20 | 21 | String[] column = { MediaStore.Images.Media.DATA }; 22 | 23 | String sel = MediaStore.Images.Media._ID + "=?"; 24 | 25 | Cursor cursor = activity.getContentResolver().query( 26 | 27 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, 28 | 29 | new String[] { id }, null); 30 | 31 | int columnIndex = cursor.getColumnIndex(column[0]); 32 | 33 | if (cursor.moveToFirst()) { 34 | 35 | path = cursor.getString(columnIndex); 36 | 37 | } 38 | 39 | cursor.close(); 40 | 41 | } else { 42 | 43 | String[] projection = { MediaStore.Images.Media.DATA }; 44 | 45 | Cursor cursor = activity.getContentResolver().query(uri, 46 | 47 | projection, null, null, null); 48 | 49 | int column_index = cursor 50 | 51 | .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 52 | 53 | cursor.moveToFirst(); 54 | 55 | path = cursor.getString(column_index); 56 | 57 | } 58 | 59 | 60 | 61 | this.path=path; 62 | 63 | 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/model/Record.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.model; 2 | 3 | import java.io.Serializable; 4 | import cn.bmob.v3.BmobObject; 5 | 6 | /** 7 | * Created by lenovo on 2016/3/31. 8 | */ 9 | 10 | public class Record extends BmobObject implements Serializable { 11 | String type; 12 | String time; 13 | String phoneNum; 14 | String update_time; 15 | String pic_url; 16 | String nickname; 17 | 18 | public String getType() { 19 | return type; 20 | } 21 | 22 | public void setType(String type) { 23 | this.type = type; 24 | } 25 | 26 | public String getTime() { 27 | return time; 28 | } 29 | 30 | public void setTime(String time) { 31 | this.time = time; 32 | } 33 | 34 | public String getPhoneNum() { 35 | return phoneNum; 36 | } 37 | 38 | public void setPhoneNum(String phoneNum) { 39 | this.phoneNum = phoneNum; 40 | } 41 | 42 | public String getUpdate_time() { 43 | return update_time; 44 | } 45 | 46 | public void setUpdate_time(String update_time) { 47 | this.update_time = update_time; 48 | } 49 | 50 | public String getPic_url() { 51 | return pic_url; 52 | } 53 | 54 | public void setPic_url(String pic_url) { 55 | this.pic_url = pic_url; 56 | } 57 | 58 | public String getNickname() { 59 | return nickname; 60 | } 61 | 62 | public void setNickname(String nickname) { 63 | this.nickname = nickname; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "Record{" + 69 | "type='" + type + '\'' + 70 | ", time='" + time + '\'' + 71 | ", phoneNum='" + phoneNum + '\'' + 72 | ", update_time='" + update_time + '\'' + 73 | ", pic_url='" + pic_url + '\'' + 74 | ", nickname='" + nickname + '\'' + 75 | '}'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/model/User.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.model; 2 | 3 | import java.io.Serializable; 4 | import cn.bmob.v3.BmobObject; 5 | import cn.bmob.v3.datatype.BmobDate; 6 | 7 | /** 8 | * Created by lenovo on 2016/3/22. 9 | */ 10 | public class User extends BmobObject implements Serializable{ 11 | 12 | // Integer user_id; 13 | String phoneNum; 14 | String pwd; 15 | String nickName; 16 | BmobDate createTime; 17 | String imgUrl; 18 | String mailNum; 19 | 20 | public String getPhoneNum() { 21 | return phoneNum; 22 | } 23 | 24 | public void setPhoneNum(String phoneNum) { 25 | this.phoneNum = phoneNum; 26 | } 27 | 28 | public String getPwd() { 29 | return pwd; 30 | } 31 | 32 | public void setPwd(String pwd) { 33 | this.pwd = pwd; 34 | } 35 | 36 | public String getNickName() { 37 | return nickName; 38 | } 39 | 40 | public void setNickName(String nickName) { 41 | this.nickName = nickName; 42 | } 43 | 44 | public BmobDate getCreateTime() { 45 | return createTime; 46 | } 47 | 48 | public void setCreateTime(BmobDate createTime) { 49 | this.createTime = createTime; 50 | } 51 | 52 | public String getImgUrl() { 53 | return imgUrl; 54 | } 55 | 56 | public void setImgUrl(String imgUrl) { 57 | this.imgUrl = imgUrl; 58 | } 59 | 60 | public String getMailNum() { 61 | return mailNum; 62 | } 63 | 64 | public void setMailNum(String mailNum) { 65 | this.mailNum = mailNum; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "User{" + 71 | "phoneNum='" + phoneNum + '\'' + 72 | ", pwd='" + pwd + '\'' + 73 | ", nickName='" + nickName + '\'' + 74 | ", createTime=" + createTime + 75 | ", imgUrl='" + imgUrl + '\'' + 76 | ", mailNum='" + mailNum + '\'' + 77 | '}'; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/BitmapUtils.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Matrix; 7 | 8 | import java.io.FileNotFoundException; 9 | 10 | public class BitmapUtils { 11 | 12 | public static Bitmap scaleBitmap(Bitmap bitmap, float scale) { 13 | Matrix matrix = new Matrix(); 14 | matrix.postScale(scale, scale); 15 | return Bitmap.createBitmap(bitmap, 0, 0, 16 | bitmap.getWidth(), 17 | bitmap.getHeight(), 18 | matrix, true); 19 | } 20 | 21 | public static Bitmap decodeSampledBitmapFromResources(Resources res, int resId, 22 | int reqWidth, int reqHeight){ 23 | final BitmapFactory.Options options = new BitmapFactory.Options(); 24 | options.inJustDecodeBounds = true; 25 | BitmapFactory.decodeResource(res, resId, options); 26 | 27 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 28 | 29 | options.inJustDecodeBounds = false; 30 | return BitmapFactory.decodeResource(res, resId, options); 31 | } 32 | private static int calculateInSampleSize(BitmapFactory.Options options, 33 | int reqWidth, int reqHeight) { 34 | final int height = options.outHeight; 35 | final int width = options.outWidth; 36 | int inSampleSize = 1; 37 | if (height > reqHeight || width > reqWidth) { 38 | final int halfHeight = height/2 ; 39 | final int halfWidth = width/2 ; 40 | while ((halfHeight / inSampleSize) > reqHeight 41 | && (halfWidth / inSampleSize) > reqWidth) { 42 | inSampleSize *= 2; 43 | } 44 | } 45 | return inSampleSize; 46 | } 47 | 48 | 49 | 50 | public static Bitmap createNoRecycleScaleBitmap(Bitmap src, int dstWidth, 51 | double dstHeight) { 52 | int k=(int) dstHeight; 53 | return Bitmap.createScaledBitmap(src, dstWidth, k, true); 54 | } 55 | //如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响 56 | public static Bitmap createScaleBitmap(Bitmap src, int dstWidth, 57 | double dstHeight) { 58 | int k=(int) dstHeight; 59 | Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, k, true); 60 | if (src != dst) { //如果没有缩放,那么不回收 61 | src.recycle(); // 释放Bitmap的native像素数组 62 | } 63 | return dst; 64 | } 65 | 66 | public static Bitmap createScaleBitmap(Bitmap src, double dstWidth, 67 | int dstHeight) { 68 | int k=(int) dstWidth; 69 | Bitmap dst = Bitmap.createScaledBitmap(src, k,dstHeight, true); 70 | if (src != dst) { //如果没有缩放,那么不回收 71 | src.recycle(); // 释放Bitmap的native像素数组 72 | } 73 | return dst; 74 | } 75 | 76 | 77 | // ��Resources�м���ͼƬ 78 | public Bitmap decodeSampledBitmapFromPath(String url, int reqWidth, int reqHeight,boolean change) 79 | throws FileNotFoundException { 80 | final BitmapFactory.Options options = new BitmapFactory.Options(); 81 | options.inJustDecodeBounds = true; 82 | 83 | 84 | 85 | BitmapFactory.decodeFile(url, options); 86 | int size; 87 | /*double re=0; 88 | re= ((double) options.outWidth)/options.outHeight;*/ 89 | if(options.outWidth>options.outHeight) 90 | size=options.outWidth; 91 | else size=options.outHeight; 92 | options.inSampleSize = calculateInSampleSize(options, size, 93 | size); // ����inSampleSize 94 | options.inJustDecodeBounds = false; 95 | Bitmap src = BitmapFactory.decodeFile(url, options); 96 | /*return src;*/// ����һ���Դ������ͼ 97 | 98 | /*if(change){ 99 | if(options.outWidth>options.outHeight) 100 | return createScaleBitmap(src, reqWidth, reqWidth/re); 101 | else 102 | return createScaleBitmap(src, reqHeight*re, reqHeight); 103 | } 104 | else 105 | return createScaleBitmap(src, reqWidth, reqWidth/re);*/ 106 | // ��һ���õ�Ŀ���С������ͼ 107 | return createScaleBitmap(src,(double)reqWidth,reqWidth); 108 | } 109 | 110 | public Bitmap decodeSampledBitmapFromPath(Resources rs, int bm, int reqWidth, int reqHeight,boolean change) throws FileNotFoundException { 111 | final BitmapFactory.Options options = new BitmapFactory.Options(); 112 | options.inJustDecodeBounds = true; 113 | 114 | 115 | 116 | BitmapFactory.decodeResource(rs, bm, options); 117 | double re=0; 118 | re= ((double) options.outWidth)/options.outHeight; 119 | options.inSampleSize = calculateInSampleSize(options, reqWidth, 120 | reqHeight); // ����inSampleSize 121 | options.inJustDecodeBounds = false; 122 | Bitmap src = BitmapFactory.decodeResource(rs, bm, options); 123 | /*return src;*/// ����һ���Դ������ͼ 124 | 125 | if(change){ 126 | if(options.outWidth>options.outHeight) 127 | return createScaleBitmap(src, reqWidth, reqWidth/re); 128 | else 129 | return createScaleBitmap(src, reqHeight*re, reqHeight); 130 | } 131 | else 132 | return createScaleBitmap(src, reqWidth, reqWidth/re); 133 | // ��һ���õ�Ŀ���С������ͼ 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/DensityUtil.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * puzzle 7 | * Created by ZQ on 2016/4/4. 8 | */ 9 | public class DensityUtil { 10 | 11 | /** 12 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 13 | */ 14 | public static int dip2px(Context context, float dpValue) { 15 | final float scale = context.getResources().getDisplayMetrics().density; 16 | return (int) (dpValue * scale + 0.5f); 17 | } 18 | 19 | /** 20 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 21 | */ 22 | public static int px2dip(Context context, float pxValue) { 23 | final float scale = context.getResources().getDisplayMetrics().density; 24 | return (int) (pxValue / scale + 0.5f); 25 | } 26 | 27 | public static float getScale(Context context){ 28 | return context.getResources().getDisplayMetrics().density; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/GameTimer.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import java.util.Timer; 7 | import java.util.TimerTask; 8 | 9 | /** 10 | * puzzle 11 | * Created by ZQ on 2016/4/24. 12 | */ 13 | public class GameTimer { 14 | public final static int MESSAGE_TIMER = 0x100; 15 | private static final int INTERVAL_TIME = 1000; 16 | private Handler[] mHandler; 17 | private Timer mTimer; 18 | private TimerTask mTimerTask; 19 | 20 | private int what; 21 | private boolean mTimerStart = false; 22 | 23 | public void recycle(){ 24 | stopTimer(); 25 | mTimer = null; 26 | mTimerTask = null; 27 | for(Handler handler : mHandler){ 28 | handler = null; 29 | } 30 | mHandler = null; 31 | } 32 | 33 | public GameTimer(Handler... handler){ 34 | this.mHandler = handler; 35 | this.what = MESSAGE_TIMER; 36 | 37 | mTimer = new Timer(); 38 | } 39 | 40 | public void startTimer(){ 41 | if(mHandler == null || mTimerStart){ 42 | return; 43 | } 44 | mTimerTask = new MyTimerTask(); 45 | mTimer.schedule(mTimerTask, INTERVAL_TIME, INTERVAL_TIME); 46 | mTimerStart = true; 47 | } 48 | 49 | public void stopTimer(){ 50 | if(!mTimerStart){ 51 | return; 52 | } 53 | mTimerStart = false; 54 | if(mTimerTask != null){ 55 | mTimerTask.cancel(); 56 | mTimerTask = null; 57 | } 58 | mTimer.cancel(); 59 | 60 | } 61 | 62 | class MyTimerTask extends TimerTask{ 63 | @Override 64 | public void run(){ 65 | if(mHandler != null){ 66 | for(Handler handler : mHandler){ 67 | Message msg = handler.obtainMessage(what); 68 | msg.sendToTarget(); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/GlobalUtils.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * Puzzle 7 | * Created by ZQ on 2016/3/24. 8 | */ 9 | public class GlobalUtils { 10 | 11 | /** 12 | * 对接收到的json字符串进行处理,去掉可能的垃圾头和垃圾尾,使其符合json格式 13 | * @param jsonString 接收到的json字符串 14 | * @return 处理后的json字符串 15 | */ 16 | public static String FixJsonString(String jsonString){ 17 | 18 | int startIndex = jsonString.indexOf('{'); 19 | int endIndex = jsonString.lastIndexOf('}'); 20 | 21 | //LogUtils.d("hehe", jsonString.substring(startIndex, endIndex + 1)); 22 | return jsonString.substring(startIndex, endIndex + 1); 23 | } 24 | 25 | /** 26 | * 27 | * @param total 28 | * @return 29 | */ 30 | public static int[] getRamdomList(int total){ 31 | int[] result = new int[total]; 32 | for(int i = 0; i < total; i++){ 33 | result[i] = i; 34 | } 35 | 36 | Random random = new Random(); 37 | for(int i = 0; i < total; i++){ 38 | int p = random.nextInt(total); 39 | int temp = result[i]; 40 | result[i] = result[p]; 41 | result[p] = temp; 42 | } 43 | 44 | random = null; 45 | return result; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/RegExUtil.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | /** 6 | * Created by lenovo on 2016/3/22. 7 | */ 8 | public class RegExUtil { 9 | 10 | //手机号输入验证 11 | public static Boolean confirmPhone(String phone){ 12 | 13 | boolean matches = Pattern.matches("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$", phone); 14 | return matches; 15 | } 16 | 17 | //密码格式要求:长度为8-20的数字,下划线或字母 18 | public static Boolean confirmPwd(String pwd){ 19 | //密码长度为8-20的数字,下划线或字母 20 | boolean matches = Pattern.matches("[a-zA-Z_0-9]{8,20}", pwd); 21 | return matches; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | /** 4 | * Created by lenovo on 2016/3/26. 5 | */ 6 | public class SecurityUtils { 7 | 8 | public static String MD5_secure(String toSecure){ 9 | String s = null; 10 | char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符 11 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 12 | try { 13 | java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); 14 | md.update(toSecure.getBytes()); 15 | byte tmp[] = md.digest(); // MD5 的计算结果是一个 128 位的长整数, 16 | // 用字节表示就是 16 个字节 17 | char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符, 18 | // 所以表示成 16 进制需要 32 个字符 19 | int k = 0; // 表示转换结果中对应的字符位置 20 | for (int i = 0; i < 16; i++) { // 从第一个字节开始,对 MD5 的每一个字节 21 | // 转换成 16 进制字符的转换 22 | byte byte0 = tmp[i]; // 取第 i 个字节 23 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, 24 | // >>> 为逻辑右移,将符号位一起右移 25 | str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换 26 | } 27 | s = new String(str); // 换后的结果转换为字符串 28 | 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | return s; 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/studio/androiddev/puzzle/utils/StaticValue.java: -------------------------------------------------------------------------------- 1 | package studio.androiddev.puzzle.utils; 2 | 3 | /** 4 | * Created by lenovo on 2016/3/22. 5 | */ 6 | public class StaticValue { 7 | public static String bmobId = "284420dcdca2ba4dbb2f1b2bb463fb35"; 8 | 9 | public static final String SP_NAME = "puzzle_sp"; 10 | public static final String SP_LEVEL = "level"; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/appearing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_shape_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_shape_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/default1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/default6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/default6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/disappearing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dish_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dish_shape_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dish_shape_middle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dish_shape_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/person_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/person_shape_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/person_shape_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/puzzle_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FreedomZZQ/Puzzle-Android/28c6738091e8ee70f507eb9b4a71ac9c51705783/app/src/main/res/drawable/puzzle_en.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_change_pwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_choose_pic.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_game.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 18 | 24 | 29 | 30 | 39 | 40 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 19 | 29 | 30 | 40 | 41 | 50 | 51 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_rank.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_register.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 18 | 28 | 29 | 39 | 40 | 50 | 51 | 52 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_user_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 17 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/choose_pic_gridview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_change_pwd.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 20 | 21 | 33 | 34 | 46 | 47 | 59 | 60 | 61 |