├── .gitignore ├── .idea ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hani │ │ └── coolcode │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hani │ │ │ └── coolcode │ │ │ ├── MainActivity.java │ │ │ ├── MyView │ │ │ ├── AnimationView.java │ │ │ └── SliderCloseView.java │ │ │ ├── ScreenRecordActivity.java │ │ │ ├── activity │ │ │ └── AnimActivity.java │ │ │ ├── service │ │ │ ├── ScreenRecordService.java │ │ │ └── ScreenUtil.java │ │ │ └── utils │ │ │ ├── CommonUtil.java │ │ │ ├── FileUtil.java │ │ │ ├── ImageUtil.java │ │ │ ├── PermissionUtils.java │ │ │ └── ToastUtil.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ ├── loading01.png │ │ ├── loading02.png │ │ ├── loading03.png │ │ ├── loading04.png │ │ ├── loading05.png │ │ ├── loading06.png │ │ ├── loading07.png │ │ ├── loading08.png │ │ ├── loading09.png │ │ ├── loading10.png │ │ ├── loading11.png │ │ ├── loading12.png │ │ ├── loading13.png │ │ ├── loading14.png │ │ ├── loading15.png │ │ ├── loading16.png │ │ ├── loading17.png │ │ ├── loading18.png │ │ ├── loading19.png │ │ ├── loading20.png │ │ ├── loading21.png │ │ ├── loading22.png │ │ ├── loading23.png │ │ ├── loading24.png │ │ ├── loading25.png │ │ ├── loading26.png │ │ ├── loading27.png │ │ ├── loading28.png │ │ ├── loading29.png │ │ ├── loading30.png │ │ ├── loading31.png │ │ ├── loading32.png │ │ ├── loading33.png │ │ ├── loading34.png │ │ ├── loading35.png │ │ ├── loading36.png │ │ ├── loading37.png │ │ ├── loading38.png │ │ ├── loading39.png │ │ ├── loading40.png │ │ ├── loading41.png │ │ ├── loading42.png │ │ ├── loading43.png │ │ ├── loading44.png │ │ ├── loading45.png │ │ ├── loading46.png │ │ ├── loading47.png │ │ ├── loading48.png │ │ ├── loading49.png │ │ ├── loading50.png │ │ ├── loading51.png │ │ ├── loading52.png │ │ ├── loading53.png │ │ ├── loading54.png │ │ ├── loading55.png │ │ ├── loading56.png │ │ ├── loading57.png │ │ ├── loading58.png │ │ ├── loading59.png │ │ ├── loading60.png │ │ ├── loading61.png │ │ ├── loading62.png │ │ ├── loading63.png │ │ ├── loading64.png │ │ ├── loading65.png │ │ ├── loading66.png │ │ ├── loading67.png │ │ ├── loading68.png │ │ ├── loading69.png │ │ ├── loading70.png │ │ ├── loading71.png │ │ ├── loading72.png │ │ ├── loading73.png │ │ ├── loading74.png │ │ └── loading75.png │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── loading.xml │ │ ├── layout │ │ ├── activity.xml │ │ ├── activity_main.xml │ │ ├── animation_layout.xml │ │ ├── inner_view.xml │ │ └── screen_record_activity.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── hani │ └── coolcode │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoolCode -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.hani.coolcode" 7 | minSdkVersion 15 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:26.1.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/hani/coolcode/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.hani.coolcode", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | import android.widget.Toast; 9 | 10 | import com.hani.coolcode.MyView.SliderCloseView; 11 | import com.hani.coolcode.utils.CommonUtil; 12 | 13 | public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 14 | 15 | private TextView mTvAdd; 16 | private SliderCloseView mSliderView; 17 | 18 | private TextView mTvInner; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | CommonUtil.init(this); 24 | setContentView(R.layout.activity); 25 | mSliderView = findViewById(R.id.sliderview); 26 | mTvAdd = findViewById(R.id.tv_add); 27 | mTvAdd.setOnClickListener(this); 28 | 29 | 30 | } 31 | 32 | 33 | 34 | @Override 35 | public void onBackPressed() { 36 | if (mSliderView.isSliderViewVisible()){ 37 | mSliderView.hiddenSliderView(); 38 | return; 39 | } 40 | super.onBackPressed(); 41 | } 42 | 43 | private void addInnerView(){ 44 | 45 | View secondView = LayoutInflater.from(this).inflate(R.layout.inner_view,null); 46 | mTvInner = secondView.findViewById(R.id.tv_inner); 47 | mTvInner.setOnClickListener(this); 48 | mSliderView.addViewToLayout(secondView,CommonUtil.getScreenWidth()); 49 | 50 | } 51 | 52 | @Override 53 | public void onClick(View v) { 54 | switch (v.getId()){ 55 | case R.id.tv_add:{ 56 | addInnerView(); 57 | break; 58 | } 59 | case R.id.tv_inner:{ 60 | Toast.makeText(this,"我在内嵌页面",Toast.LENGTH_SHORT).show(); 61 | break; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/MyView/AnimationView.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.MyView; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.os.Handler; 8 | import android.os.HandlerThread; 9 | import android.os.Message; 10 | import android.support.annotation.Nullable; 11 | import android.util.AttributeSet; 12 | import android.view.Gravity; 13 | import android.view.View; 14 | 15 | 16 | import com.hani.coolcode.utils.ImageUtil; 17 | 18 | import java.lang.ref.WeakReference; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by Administrator on 2018/3/12 0012. 24 | */ 25 | 26 | public class AnimationView extends View implements Handler.Callback { 27 | 28 | public static final int DEFAULT_ANIM_TIME = 100; 29 | 30 | public static final int PROCESS_DATA = 1; 31 | public static final int PROCESS_ANIM_FINISH = 1 << 1; 32 | public static final int PROCESS_DELAY = 1 << 2; 33 | 34 | 35 | 36 | public AnimData mCurAnimData; 37 | public int mCurAnimPos; 38 | public boolean mIsRepeat; 39 | 40 | public int mAnimTime; 41 | 42 | private Handler mHandler ; 43 | private ProcessAnimThread mProcessThread; 44 | private Bitmap mCurShowBmp; 45 | 46 | private List mAnimDataList = new ArrayList<>(); 47 | 48 | public AnimationView(Context context) { 49 | this(context,null); 50 | } 51 | 52 | public AnimationView(Context context, @Nullable AttributeSet attrs) { 53 | this(context, attrs,0); 54 | } 55 | 56 | public AnimationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 57 | super(context, attrs, defStyleAttr); 58 | init(); 59 | } 60 | 61 | private void init(){ 62 | mHandler = new Handler(this); 63 | mProcessThread = new ProcessAnimThread(getContext(),mHandler); 64 | mAnimTime = DEFAULT_ANIM_TIME; 65 | } 66 | 67 | public void setIsRepeat(boolean repeat){ 68 | mIsRepeat = repeat; 69 | } 70 | private int mGravity; 71 | public void SetGravity(int gravity) 72 | { 73 | mGravity = gravity; 74 | invalidate(); 75 | } 76 | 77 | public void setData(List list){ 78 | if (list != null ){ 79 | mAnimDataList.addAll(list); 80 | } 81 | } 82 | 83 | private Matrix mTempMatrix = new Matrix(); 84 | @Override 85 | protected void onDraw(Canvas canvas) { 86 | 87 | if(mCurShowBmp != null && !mCurShowBmp.isRecycled()) 88 | { 89 | int x = 0; 90 | int y = 0; 91 | float scaleX = 1f; 92 | float scaleY = 1f; 93 | switch(mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) 94 | { 95 | case Gravity.LEFT: 96 | x = 0; 97 | break; 98 | 99 | case Gravity.RIGHT: 100 | x = this.getWidth() - mCurShowBmp.getWidth(); 101 | break; 102 | 103 | case Gravity.CENTER_HORIZONTAL: 104 | x = (this.getWidth() - mCurShowBmp.getWidth()) / 2; 105 | break; 106 | 107 | case Gravity.FILL_HORIZONTAL: 108 | { 109 | int w = mCurShowBmp.getWidth(); 110 | if(w > 0) 111 | { 112 | scaleX = (float)this.getWidth() / (float)w; 113 | } 114 | break; 115 | } 116 | 117 | default: 118 | break; 119 | } 120 | switch(mGravity & Gravity.VERTICAL_GRAVITY_MASK) 121 | { 122 | case Gravity.TOP: 123 | y = 0; 124 | break; 125 | 126 | case Gravity.BOTTOM: 127 | y = this.getHeight() - mCurShowBmp.getHeight(); 128 | break; 129 | 130 | case Gravity.CENTER_VERTICAL: 131 | y = (this.getHeight() - mCurShowBmp.getHeight()) / 2; 132 | break; 133 | 134 | case Gravity.FILL_VERTICAL: 135 | { 136 | int h = mCurShowBmp.getHeight(); 137 | if(h > 0) 138 | { 139 | scaleY = (float)this.getHeight() / (float)h; 140 | } 141 | break; 142 | } 143 | 144 | default: 145 | break; 146 | } 147 | if(scaleX == 1 && scaleY != 1) 148 | { 149 | scaleX = scaleY; 150 | switch(mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) 151 | { 152 | case Gravity.RIGHT: 153 | x = this.getWidth() - (int)(mCurShowBmp.getWidth() * scaleX); 154 | break; 155 | case Gravity.CENTER_HORIZONTAL: 156 | x = (this.getWidth() - (int)(mCurShowBmp.getWidth() * scaleX)) / 2; 157 | break; 158 | } 159 | } 160 | else if(scaleX != 1 && scaleY == 1) 161 | { 162 | scaleY = scaleX; 163 | switch(mGravity & Gravity.VERTICAL_GRAVITY_MASK) 164 | { 165 | case Gravity.BOTTOM: 166 | y = this.getHeight() - (int)(mCurShowBmp.getHeight() * scaleY); 167 | break; 168 | case Gravity.CENTER_VERTICAL: 169 | y = (this.getHeight() - (int)(mCurShowBmp.getHeight() * scaleY)) / 2; 170 | break; 171 | } 172 | } 173 | mTempMatrix.reset(); 174 | mTempMatrix.postScale(scaleX, scaleY); 175 | mTempMatrix.postTranslate(x, y); 176 | canvas.drawBitmap(mCurShowBmp, mTempMatrix, null); 177 | } 178 | } 179 | 180 | private boolean mHasStarted = false; 181 | public void start(){ 182 | 183 | mHasStarted = true; 184 | if (mWidth == 0 || mHeight == 0 ){ 185 | return; 186 | } 187 | 188 | startPlay(); 189 | 190 | } 191 | 192 | private void startPlay() { 193 | 194 | if ( mAnimDataList != null && mAnimDataList.size() > 0 ){ 195 | 196 | mCurAnimPos = 0; 197 | AnimData animData = mAnimDataList.get(mCurAnimPos); 198 | mCurShowBmp = ImageUtil.getBitmap(getContext(),animData.filePath,mWidth,mHeight); 199 | invalidate(); 200 | if (mListener != null ){ 201 | mListener.onAnimChange(mCurAnimPos,mCurShowBmp); 202 | } 203 | checkIsPlayNext(); 204 | } 205 | } 206 | 207 | private void playNext(final int curAnimPosition ){ 208 | 209 | Message msg = Message.obtain(); 210 | msg.what = PROCESS_DELAY; 211 | msg.arg1 = curAnimPosition; 212 | mHandler.sendMessageDelayed(msg,mAnimTime); 213 | } 214 | 215 | @Override 216 | protected void onAttachedToWindow() { 217 | super.onAttachedToWindow(); 218 | 219 | } 220 | 221 | @Override 222 | protected void onDetachedFromWindow() { 223 | super.onDetachedFromWindow(); 224 | quit(); 225 | } 226 | 227 | private void quit(){ 228 | 229 | mHasStarted = false; 230 | if (mProcessThread != null ){ 231 | mProcessThread.clearAll(); 232 | } 233 | } 234 | 235 | private int mWidth; 236 | private int mHeight; 237 | @Override 238 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 239 | super.onSizeChanged(w, h, oldw, oldh); 240 | mWidth = w; 241 | mHeight = h; 242 | if (mProcessThread != null ){ 243 | mProcessThread.setSize(w,h); 244 | } 245 | if (mHasStarted){ 246 | startPlay(); 247 | } 248 | 249 | } 250 | 251 | private boolean mHavePause = false; 252 | public void pause(){ 253 | mHavePause = true; 254 | mHandler.removeMessages(PROCESS_DELAY); 255 | } 256 | 257 | public void resume(){ 258 | if (mHavePause && mHasStarted){ 259 | checkIsPlayNext(); 260 | 261 | } 262 | } 263 | @Override 264 | public boolean handleMessage(Message msg) { 265 | //此 handleMessage 在主线程被调用 266 | switch (msg.what){ 267 | case PROCESS_ANIM_FINISH:{ 268 | 269 | Bitmap bitmap = (Bitmap) msg.obj; 270 | if (bitmap != null){ 271 | if (mCurShowBmp != null ){ 272 | mCurShowBmp.recycle(); 273 | mCurShowBmp = null; 274 | } 275 | mCurShowBmp = bitmap; 276 | if (mListener != null ){ 277 | mListener.onAnimChange(mCurAnimPos,bitmap); 278 | } 279 | invalidate(); 280 | 281 | } 282 | checkIsPlayNext(); 283 | break; 284 | } 285 | case PROCESS_DELAY:{ 286 | int curAnimPosition = msg.arg1; 287 | AnimData data = mAnimDataList.get(curAnimPosition); 288 | mProcessThread.processData(data); 289 | break; 290 | } 291 | } 292 | return true; 293 | } 294 | private void checkIsPlayNext() { 295 | mCurAnimPos ++; 296 | if ( mCurAnimPos >= mAnimDataList.size() ){ 297 | if (mIsRepeat){ 298 | mCurAnimPos = 0; 299 | playNext(mCurAnimPos); 300 | } else { 301 | if ( mListener != null ){ 302 | mListener.onAnimEnd(); 303 | } 304 | } 305 | } else { 306 | playNext(mCurAnimPos); 307 | } 308 | } 309 | private AnimCallBack mListener; 310 | public void setAnimCallBack(AnimCallBack callBack){ 311 | mListener = callBack; 312 | } 313 | 314 | public interface AnimCallBack{ 315 | 316 | void onAnimChange(int position, Bitmap bitmap); 317 | void onAnimEnd(); 318 | } 319 | 320 | public static class AnimData{ 321 | public Object filePath; 322 | 323 | } 324 | public static class ProcessAnimThread{ 325 | 326 | private HandlerThread mHandlerThread; 327 | private Handler mProcessHandler; 328 | private Handler mUiHandler; 329 | 330 | private AnimData mCurAnimData; 331 | 332 | private int mWidth; 333 | private int mHeight; 334 | private WeakReference mContext; 335 | 336 | public ProcessAnimThread(Context context, Handler handler){ 337 | mUiHandler = handler; 338 | mContext = new WeakReference(context); 339 | init(); 340 | } 341 | 342 | public void setSize(int width,int height){ 343 | mWidth = width; 344 | mHeight = height; 345 | } 346 | 347 | private void init(){ 348 | 349 | mHandlerThread = new HandlerThread("process_anim_thread"); 350 | mHandlerThread.start(); 351 | 352 | mProcessHandler = new Handler(mHandlerThread.getLooper(), new Handler.Callback() { 353 | @Override 354 | public boolean handleMessage(Message msg) { 355 | // 消息是在子线程 HandlerThread 里面被处理,所以这里的 handleMessage 在 356 | //子线程里被调用 357 | switch (msg.what){ 358 | case PROCESS_DATA:{ 359 | AnimData animData = (AnimData) msg.obj; 360 | Bitmap bitmap = ImageUtil.getBitmap(mContext.get(),animData.filePath,mWidth,mHeight); 361 | if (bitmap != null ){ 362 | Message finishMsg = Message.obtain(); 363 | finishMsg.what = PROCESS_ANIM_FINISH; 364 | finishMsg.obj = bitmap; 365 | //消息处理完毕,使用主线程的 Handler 将消息发送到主线程 366 | mUiHandler.sendMessage(finishMsg); 367 | } 368 | break; 369 | } 370 | } 371 | return true; 372 | } 373 | }); 374 | 375 | } 376 | 377 | public void processData(AnimData animData){ 378 | 379 | if ( animData != null ){ 380 | Message msg = Message.obtain(); 381 | msg.what = PROCESS_DATA; 382 | msg.obj = animData; 383 | mProcessHandler.sendMessage(msg); 384 | } 385 | 386 | } 387 | public void clearAll(){ 388 | 389 | mHandlerThread.quit(); 390 | mHandlerThread = null; 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/MyView/SliderCloseView.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.MyView; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.graphics.Color; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.view.MotionEventCompat; 9 | import android.util.AttributeSet; 10 | import android.util.Log; 11 | import android.view.MotionEvent; 12 | import android.view.VelocityTracker; 13 | import android.view.View; 14 | import android.view.ViewConfiguration; 15 | import android.view.ViewGroup; 16 | import android.view.animation.AccelerateDecelerateInterpolator; 17 | import android.widget.FrameLayout; 18 | 19 | 20 | /** 仿 iOS 左边缘右滑关闭页面 21 | * Created by admin on 2017/8/14. 22 | */ 23 | 24 | public class SliderCloseView extends FrameLayout { 25 | 26 | //当前有效的PointerId,默认为第一个按下屏幕的手指 27 | private int mActivePointerId; 28 | //true,mSliderView 当前正被拖拽 29 | private boolean mIsBeingDrag; 30 | private float mInitDownX; 31 | private float mInitDownY; 32 | // private float mLastDownX; 33 | 34 | private Context mContext; 35 | 36 | private static final float INVALID_VALUE = -1f; 37 | private int mTouchSlop; 38 | 39 | private OnSliderListener mSliderListener; 40 | 41 | private View mSliderView; 42 | 43 | private float mCurTranslationX; 44 | private static final int DEFAULT_ANIM_TIME = 300; 45 | private static final float HORIZANTAL_SPEED = 2500f; 46 | private boolean mIsAnimating; 47 | 48 | //true,mSliderView显示出来 49 | private boolean mIsSliderShowing; 50 | 51 | //true,除非动画关闭mSliderView 52 | private boolean mIsToHiddlenPage; 53 | 54 | private VelocityTracker mVelocityTracker; 55 | 56 | public SliderCloseView(Context context) { 57 | this(context,null); 58 | } 59 | 60 | public SliderCloseView(Context context, @Nullable AttributeSet attrs) { 61 | this(context, attrs,0); 62 | } 63 | 64 | public SliderCloseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 65 | super(context, attrs, defStyleAttr); 66 | mContext = context; 67 | init(); 68 | } 69 | 70 | private void init(){ 71 | 72 | mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); 73 | setBackgroundColor(Color.TRANSPARENT); 74 | } 75 | 76 | public void setSliderListener(OnSliderListener listener){ 77 | mSliderListener = listener; 78 | } 79 | 80 | public void addViewToLayout(View view, int screenWidth){ 81 | 82 | if(view != null){ 83 | //需要设置Clickable,子view必须消费掉Down事件,不然 84 | //后续的 move,up 事件是接收不到的 85 | view.setClickable(true); 86 | mSliderView = view; 87 | LayoutParams frParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 88 | this.addView(mSliderView,frParams); 89 | 90 | mCurTranslationX = screenWidth; 91 | //先设置 X 方向的偏移,再开启动画 92 | //视觉上就可以看到View是从右到左进入页面的 93 | mSliderView.setTranslationX(mCurTranslationX); 94 | actionEnd(false); 95 | } 96 | } 97 | 98 | public void clearView(){ 99 | 100 | if(mSliderView != null){ 101 | removeView(mSliderView); 102 | mSliderView = null; 103 | 104 | } 105 | } 106 | 107 | private void removeViewFromLayout(){ 108 | 109 | if(mSliderView != null){ 110 | 111 | mCurTranslationX = 0; 112 | mSliderView.setTranslationX(mCurTranslationX); 113 | actionEnd(true); 114 | 115 | } 116 | 117 | } 118 | public void hiddenSliderView(){ 119 | mIsToHiddlenPage = true; 120 | removeViewFromLayout(); 121 | 122 | } 123 | 124 | public boolean isSliderViewVisible(){ 125 | return mSliderView != null && mIsSliderShowing; 126 | } 127 | 128 | 129 | @Override 130 | public boolean onInterceptTouchEvent(MotionEvent ev) { 131 | int action = MotionEventCompat.getActionMasked(ev); 132 | switch (action){ 133 | case MotionEvent.ACTION_DOWN:{ 134 | //Down 事件触发时,表示有第一个手指接触到屏幕了 135 | //获取第一个手指Down 的PointerId 136 | mActivePointerId = ev.getPointerId(0); 137 | mInitDownX = getMotionEventX(ev); 138 | // mLastDownX = mInitDownX; 139 | mInitDownY = getMotionEventY(ev); 140 | if(mInitDownX == INVALID_VALUE || mInitDownY == INVALID_VALUE){ 141 | mIsBeingDrag = false; 142 | return super.onInterceptTouchEvent(ev); 143 | } 144 | break; 145 | } 146 | case MotionEvent.ACTION_MOVE:{ 147 | float x = getMotionEventX(ev); 148 | float y = getMotionEventY(ev); 149 | 150 | float diffX = x - mInitDownX; 151 | float diffY = y - mInitDownY; 152 | 153 | //手指按下的初始位置在屏幕左侧的 十分之一的范围里,并且 X 方向的距离 154 | //比 Y 方向上的多,也超过最小的 mTouchSlop,就可以认为已经开始拖拽了 155 | if( mInitDownX < getWidth() / 10 && Math.abs(diffX) >= mTouchSlop 156 | && Math.abs(diffX) > Math.abs(diffY)){ 157 | mIsBeingDrag = true; 158 | } 159 | 160 | break; 161 | 162 | } 163 | case MotionEvent.ACTION_POINTER_UP:{ 164 | //当有多个手指按在屏幕上,其中一个手指抬起时会进入此方法 165 | onSecondaryPointerUp(ev); 166 | break; 167 | } 168 | case MotionEvent.ACTION_CANCEL: 169 | case MotionEvent.ACTION_UP:{ 170 | //最后一个手指抬起,或者事件被父view 拦截时,恢复到初始状态 171 | mIsBeingDrag = false; 172 | mInitDownX = 0; 173 | mInitDownY = 0; 174 | // mLastDownX = 0; 175 | mActivePointerId = MotionEvent.INVALID_POINTER_ID; 176 | break; 177 | } 178 | } 179 | 180 | //如果 mIsBeingDrag 为 true ,说明已经触发了滑动的条件 181 | //事件会被拦截,交给 onTouchEvent 处理 182 | return mIsBeingDrag || super.onInterceptTouchEvent(ev); 183 | } 184 | 185 | 186 | 187 | 188 | @Override 189 | public boolean onTouchEvent(MotionEvent event) { 190 | 191 | switch (MotionEventCompat.getActionMasked(event)){ 192 | 193 | case MotionEvent.ACTION_DOWN:{ 194 | mInitDownX = getMotionEventX(event); 195 | mInitDownY = getMotionEventY(event); 196 | break; 197 | } 198 | case MotionEvent.ACTION_MOVE:{ 199 | 200 | //初始化速度追踪器,用以追踪手指的滑动速度 201 | if(mVelocityTracker == null){ 202 | mVelocityTracker = VelocityTracker.obtain(); 203 | } 204 | mVelocityTracker.addMovement(event); 205 | 206 | float x = getMotionEventX(event); 207 | float diffX = x - mInitDownX; 208 | 209 | if( diffX >= 0 ){ 210 | //手指是向右滑动的,偏移 SliderView 211 | if(mSliderView != null){ 212 | mSliderView.setTranslationX(diffX); 213 | } 214 | } 215 | 216 | if(mSliderListener != null){ 217 | mSliderListener.onProgress((int) diffX,diffX * 1.0f / getWidth(),mSliderView); 218 | } 219 | 220 | Log.w("lala","getScrollX: "+diffX+" rate: "+ diffX * 1.0f / getWidth() ); 221 | 222 | // 左侧即将滑出屏幕 223 | 224 | return true; 225 | } 226 | case MotionEvent.ACTION_POINTER_UP: 227 | //当有多个手指按在屏幕上,其中一个手指抬起时会进入此方法 228 | onSecondaryPointerUp(event); 229 | break; 230 | case MotionEvent.ACTION_CANCEL: 231 | case MotionEvent.ACTION_UP:{ 232 | 233 | if(mVelocityTracker != null && mActivePointerId != MotionEvent.INVALID_POINTER_ID){ 234 | //获取手指抬起的一瞬间,获取 X 方向上的速度 235 | mVelocityTracker.computeCurrentVelocity(1000); 236 | float xVelocity = mVelocityTracker.getXVelocity(mActivePointerId); 237 | Log.w("tracker","X velocity: "+xVelocity); 238 | 239 | mVelocityTracker.clear(); 240 | mVelocityTracker = null; 241 | if( xVelocity >= HORIZANTAL_SPEED && mSliderView != null){ 242 | //如果水平的速度超过了特定值,可以认为是手指 fling 操作 243 | //让 sliderview 做向右的动画操作,关闭页面 244 | mCurTranslationX = mSliderView.getTranslationX(); 245 | 246 | actionEnd(true); 247 | break; 248 | 249 | } 250 | 251 | } 252 | 253 | // 根据手指释放时的位置决定回弹还是关闭 254 | float x = getMotionEventX(event); 255 | float diffX = x - mInitDownX; 256 | if( diffX == 0 ){ 257 | //手指滑动了 sliderview,但是最后手指抬起时,让它回到了原来的位置 258 | if(mSliderListener != null){ 259 | mSliderListener.onSliderShow(mSliderView); 260 | } 261 | resetValue(); 262 | 263 | } else if( diffX == getWidth()){ 264 | if(mSliderListener != null){ 265 | mSliderListener.onSliderHidden(); 266 | } 267 | resetValue(); 268 | 269 | } else { 270 | 271 | if (mSliderView != null ){ 272 | 273 | mCurTranslationX = mSliderView.getTranslationX(); 274 | //sliderview 在 水平方向的偏移少于父布局的宽度的一半 275 | //则让其回到原位,否则做动画打开 276 | if(mCurTranslationX < getWidth() / 2){ 277 | actionEnd(false); 278 | } 279 | else { 280 | actionEnd(true); 281 | } 282 | } 283 | 284 | } 285 | 286 | break; 287 | } 288 | 289 | } 290 | return super.onTouchEvent(event); 291 | } 292 | 293 | 294 | /** 295 | * 开启动画, 296 | * @param toRight true,mSliderView滑向右边,否则,滑向左边 297 | */ 298 | private void actionEnd(boolean toRight){ 299 | 300 | ValueAnimator animator = getAnimator(toRight); 301 | animator.start(); 302 | } 303 | 304 | private ValueAnimator getAnimator(final boolean toRight){ 305 | 306 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(mCurTranslationX, toRight ? getWidth():0f); 307 | valueAnimator.setDuration(DEFAULT_ANIM_TIME); 308 | valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); 309 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 310 | @Override 311 | public void onAnimationUpdate(ValueAnimator animation) { 312 | float value = (float) animation.getAnimatedValue(); 313 | if(mSliderView != null){ 314 | mSliderView.setTranslationX(value); 315 | 316 | } 317 | 318 | if(mSliderListener != null){ 319 | mSliderListener.onProgress((int) value,value * 1.0f / getWidth(),mSliderView); 320 | } 321 | 322 | 323 | } 324 | }); 325 | 326 | valueAnimator.addListener(new Animator.AnimatorListener() { 327 | @Override 328 | public void onAnimationStart(Animator animation) { 329 | mIsAnimating = true; 330 | 331 | } 332 | 333 | @Override 334 | public void onAnimationEnd(Animator animation) { 335 | 336 | 337 | 338 | if(toRight){ 339 | 340 | if(mSliderListener != null){ 341 | mSliderListener.onSliderHidden(); 342 | } 343 | mIsSliderShowing = false; 344 | mCurTranslationX = getWidth(); 345 | 346 | clearView(); 347 | if(mIsToHiddlenPage){ 348 | mIsToHiddlenPage = false; 349 | } 350 | 351 | } 352 | else { 353 | 354 | if(mSliderListener != null){ 355 | mSliderListener.onSliderShow(mSliderView); 356 | } 357 | mIsSliderShowing = true; 358 | mCurTranslationX = 0; 359 | } 360 | 361 | resetValue(); 362 | 363 | 364 | } 365 | 366 | @Override 367 | public void onAnimationCancel(Animator animation) { 368 | 369 | } 370 | 371 | @Override 372 | public void onAnimationRepeat(Animator animation) { 373 | 374 | } 375 | }); 376 | 377 | return valueAnimator; 378 | 379 | 380 | } 381 | 382 | 383 | /** 384 | * 清楚一些记录的变量 385 | */ 386 | private void resetValue(){ 387 | 388 | mInitDownX = 0; 389 | mInitDownY = 0; 390 | 391 | mIsBeingDrag = false; 392 | mIsAnimating = false; 393 | mActivePointerId = MotionEvent.INVALID_POINTER_ID; 394 | 395 | } 396 | 397 | /** 398 | * 当屏幕上有手指抬起时,判断是不是 Down 事件触发时记录的 PointerId 399 | * 如果是的话,选其他手指的 PointerId 作为 mActivePointerId 400 | * @param event 401 | */ 402 | private void onSecondaryPointerUp(MotionEvent event){ 403 | int pointerIndex = MotionEventCompat.getActionIndex(event); 404 | int pointerId = event.getPointerId(pointerIndex); 405 | if(pointerId == mActivePointerId){ 406 | int newPointerIndex = pointerIndex == 0 ? 1: 0; 407 | mActivePointerId = event.getPointerId(newPointerIndex); 408 | } 409 | 410 | } 411 | 412 | 413 | /** 414 | * 获取当前有效PointerId 的 X 值 415 | * @param event 416 | * @return 417 | */ 418 | private float getMotionEventX(MotionEvent event){ 419 | int pointerIndex = event.findPointerIndex(mActivePointerId); 420 | return pointerIndex < 0 ? INVALID_VALUE: event.getX(pointerIndex); 421 | } 422 | 423 | /** 424 | * 获取当前有效PointerId 的 Y 值 425 | * @param event 426 | * @return 427 | */ 428 | private float getMotionEventY(MotionEvent event){ 429 | int pointerIndex = event.findPointerIndex(mActivePointerId); 430 | return pointerIndex < 0 ? INVALID_VALUE: event.getY(pointerIndex); 431 | } 432 | 433 | 434 | 435 | public interface OnSliderListener{ 436 | //判断打开的进度 437 | void onProgress(int current, float progress,View view); 438 | //页面关闭 439 | void onSliderHidden(); 440 | //页面打开 441 | void onSliderShow(View page); 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/ScreenRecordActivity.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.ServiceConnection; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.os.IBinder; 11 | import android.support.annotation.Nullable; 12 | import android.support.v7.app.AlertDialog; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.view.View; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.hani.coolcode.service.ScreenRecordService; 19 | import com.hani.coolcode.service.ScreenUtil; 20 | import com.hani.coolcode.utils.CommonUtil; 21 | import com.hani.coolcode.utils.PermissionUtils; 22 | import com.hani.coolcode.utils.ToastUtil; 23 | 24 | import static android.support.v4.content.PermissionChecker.PERMISSION_DENIED; 25 | 26 | public class ScreenRecordActivity extends AppCompatActivity implements View.OnClickListener { 27 | 28 | private TextView mTvStart; 29 | private TextView mTvEnd; 30 | 31 | private TextView mTvTime; 32 | 33 | private int REQUEST_CODE = 1; 34 | @Override 35 | protected void onCreate(@Nullable Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.screen_record_activity); 38 | 39 | CommonUtil.init(this); 40 | PermissionUtils.checkPermission(this); 41 | mTvStart = findViewById(R.id.tv_start); 42 | mTvStart.setOnClickListener(this); 43 | 44 | mTvTime = findViewById(R.id.tv_record_time); 45 | 46 | mTvEnd = findViewById(R.id.tv_end); 47 | mTvEnd.setOnClickListener(this); 48 | 49 | startScreenRecordService(); 50 | 51 | } 52 | 53 | private ServiceConnection mServiceConnection; 54 | 55 | /** 56 | * 开启录制 Service 57 | */ 58 | private void startScreenRecordService(){ 59 | 60 | mServiceConnection = new ServiceConnection() { 61 | @Override 62 | public void onServiceConnected(ComponentName name, IBinder service) { 63 | ScreenRecordService.RecordBinder recordBinder = (ScreenRecordService.RecordBinder) service; 64 | ScreenRecordService screenRecordService = recordBinder.getRecordService(); 65 | ScreenUtil.setScreenService(screenRecordService); 66 | } 67 | 68 | @Override 69 | public void onServiceDisconnected(ComponentName name) { 70 | 71 | } 72 | }; 73 | 74 | Intent intent = new Intent(this, ScreenRecordService.class); 75 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE); 76 | 77 | ScreenUtil.addRecordListener(recordListener); 78 | } 79 | 80 | @Override 81 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 82 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 83 | for (int temp : grantResults) { 84 | if (temp == PERMISSION_DENIED) { 85 | AlertDialog dialog = new AlertDialog.Builder(this).setTitle("申请权限").setMessage("这些权限很重要").setNegativeButton("取消", new DialogInterface.OnClickListener() { 86 | @Override 87 | public void onClick(DialogInterface dialog, int which) { 88 | ToastUtil.show(ScreenRecordActivity.this, "取消"); 89 | } 90 | }).setPositiveButton("设置", new DialogInterface.OnClickListener() { 91 | @Override 92 | public void onClick(DialogInterface dialog, int which) { 93 | Intent intent = new Intent(); 94 | intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 95 | intent.setData(Uri.parse("package:" + ScreenRecordActivity.this.getPackageName())); 96 | ScreenRecordActivity.this.startActivity(intent); 97 | } 98 | }).create(); 99 | dialog.show(); 100 | break; 101 | } 102 | } 103 | } 104 | 105 | private ScreenUtil.RecordListener recordListener = new ScreenUtil.RecordListener() { 106 | @Override 107 | public void onStartRecord() { 108 | 109 | } 110 | 111 | @Override 112 | public void onPauseRecord() { 113 | 114 | } 115 | 116 | @Override 117 | public void onResumeRecord() { 118 | 119 | } 120 | 121 | @Override 122 | public void onStopRecord(String stopTip) { 123 | ToastUtil.show(ScreenRecordActivity.this,stopTip); 124 | } 125 | 126 | @Override 127 | public void onRecording(String timeTip) { 128 | mTvTime.setText(timeTip); 129 | } 130 | }; 131 | 132 | @Override 133 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK){ 136 | try { 137 | ScreenUtil.setUpData(resultCode,data); 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | } else { 142 | ToastUtil.show(this,"拒绝录屏"); 143 | } 144 | } 145 | 146 | @Override 147 | public void onClick(View v) { 148 | 149 | switch (v.getId()){ 150 | case R.id.tv_start:{ 151 | ScreenUtil.startScreenRecord(this,REQUEST_CODE); 152 | break; 153 | } 154 | case R.id.tv_end:{ 155 | ScreenUtil.stopScreenRecord(this); 156 | break; 157 | } 158 | } 159 | 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/activity/AnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.activity; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.drawable.AnimationDrawable; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.hani.coolcode.MyView.AnimationView; 14 | import com.hani.coolcode.R; 15 | 16 | import java.util.ArrayList; 17 | 18 | /** 19 | * Created by Administrator on 2018/3/14 0014. 20 | */ 21 | 22 | public class AnimActivity extends AppCompatActivity implements View.OnClickListener{ 23 | 24 | private static final String TAG = "AnimActivity"; 25 | private TextView mTvPlay; 26 | private AnimationView mAnimView; 27 | 28 | private ImageView mIvAnim; 29 | private AnimationDrawable mAnimDrawable; 30 | 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.animation_layout); 35 | mTvPlay = (TextView) findViewById(R.id.tv_play); 36 | mTvPlay.setOnClickListener(this); 37 | 38 | 39 | mIvAnim = findViewById(R.id.iv_showAnim); 40 | mAnimView = (AnimationView) findViewById(R.id.anim); 41 | mAnimView.setData(getAnimationData()); 42 | mAnimView.setAnimCallBack(new AnimationView.AnimCallBack() { 43 | @Override 44 | public void onAnimChange(int position, Bitmap bitmap) { 45 | Log.w(TAG,"position: "+position); 46 | } 47 | 48 | @Override 49 | public void onAnimEnd() { 50 | Log.w(TAG,"onAnimEnd"); 51 | } 52 | }); 53 | } 54 | 55 | private ArrayList getAnimationData() 56 | { 57 | ArrayList datas = new ArrayList<>(); 58 | AnimationView.AnimData data; 59 | int resId; 60 | String fileName = "loading"; 61 | for (int i = 1; i <= 75; i++) { 62 | if (i < 10) { 63 | fileName += "0"; 64 | } 65 | resId = getResources().getIdentifier(fileName + i, "drawable", getPackageName()); 66 | data = new AnimationView.AnimData(); 67 | data.filePath = resId; 68 | datas.add(data); 69 | fileName = "loading"; 70 | } 71 | return datas; 72 | } 73 | 74 | @Override 75 | protected void onPause() { 76 | super.onPause(); 77 | mAnimView.pause(); 78 | } 79 | 80 | @Override 81 | protected void onResume() { 82 | super.onResume(); 83 | mAnimView.resume(); 84 | } 85 | 86 | private void playFrameAnimation(){ 87 | mIvAnim.setImageResource(R.drawable.loading); 88 | mAnimDrawable = (AnimationDrawable) mIvAnim.getDrawable(); 89 | mAnimDrawable.start(); 90 | } 91 | 92 | @Override 93 | public void onClick(View v) { 94 | switch (v.getId()){ 95 | case R.id.tv_play:{ 96 | // playFrameAnimation(); 97 | mAnimView.start(); 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/service/ScreenRecordService.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.service; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Service; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.hardware.display.DisplayManager; 8 | import android.hardware.display.VirtualDisplay; 9 | import android.media.MediaRecorder; 10 | import android.media.projection.MediaProjection; 11 | import android.media.projection.MediaProjectionManager; 12 | import android.os.Binder; 13 | import android.os.Build; 14 | import android.os.Environment; 15 | import android.os.Handler; 16 | import android.os.IBinder; 17 | import android.os.Looper; 18 | import android.os.Message; 19 | import android.support.annotation.RequiresApi; 20 | 21 | 22 | import com.hani.coolcode.R; 23 | import com.hani.coolcode.utils.CommonUtil; 24 | import com.hani.coolcode.utils.FileUtil; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | 29 | 30 | 31 | /** 32 | * Created by admin on 2018/3/28. 33 | */ 34 | 35 | public class ScreenRecordService extends Service implements Handler.Callback{ 36 | 37 | private MediaProjectionManager mProjectionManager; 38 | private MediaProjection mMediaProjection; 39 | private MediaRecorder mMediaRecorder; 40 | private VirtualDisplay mVirtualDisplay; 41 | 42 | private boolean mIsRunning; 43 | private int mRecordWidth = CommonUtil.getScreenWidth(); 44 | private int mRecordHeight = CommonUtil.getScreenHeight(); 45 | private int mScreenDpi = CommonUtil.getScreenDpi(); 46 | 47 | 48 | private int mResultCode; 49 | private Intent mResultData; 50 | 51 | //录屏文件的保存地址 52 | private String mRecordFilePath; 53 | 54 | private Handler mHandler; 55 | //已经录制多少秒了 56 | private int mRecordSeconds = 0; 57 | 58 | private static final int MSG_TYPE_COUNT_DOWN = 110; 59 | 60 | @Override 61 | public IBinder onBind(Intent intent) { 62 | return new RecordBinder(); 63 | } 64 | 65 | @Override 66 | public int onStartCommand(Intent intent, int flags, int startId) { 67 | return START_STICKY; 68 | } 69 | 70 | @Override 71 | public void onCreate() { 72 | super.onCreate(); 73 | 74 | 75 | mIsRunning = false; 76 | mMediaRecorder = new MediaRecorder(); 77 | mHandler = new Handler(Looper.getMainLooper(),this); 78 | 79 | } 80 | 81 | @Override 82 | public void onDestroy() { 83 | super.onDestroy(); 84 | } 85 | 86 | 87 | public boolean isReady(){ 88 | return mMediaProjection != null && mResultData != null; 89 | } 90 | 91 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 92 | public void clearRecordElement(){ 93 | clearAll(); 94 | if (mMediaRecorder != null){ 95 | mMediaRecorder.reset(); 96 | mMediaRecorder.release(); 97 | mMediaRecorder = null; 98 | } 99 | mResultData = null; 100 | mIsRunning =false; 101 | } 102 | 103 | public boolean ismIsRunning() { 104 | return mIsRunning; 105 | } 106 | 107 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 108 | public void setResultData(int resultCode, Intent resultData){ 109 | mResultCode = resultCode; 110 | mResultData = resultData; 111 | 112 | mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); 113 | if (mProjectionManager != null){ 114 | mMediaProjection = mProjectionManager.getMediaProjection(mResultCode,mResultData); 115 | } 116 | } 117 | 118 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 119 | public boolean startRecord() { 120 | if ( mIsRunning) { 121 | return false; 122 | } 123 | if (mMediaProjection == null){ 124 | mMediaProjection = mProjectionManager.getMediaProjection(mResultCode,mResultData); 125 | 126 | } 127 | 128 | setUpMediaRecorder(); 129 | createVirtualDisplay(); 130 | mMediaRecorder.start(); 131 | 132 | ScreenUtil.startRecord(); 133 | //最多录制三分钟 134 | mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN,1000); 135 | 136 | mIsRunning = true; 137 | 138 | // Log.w("lala","startRecord "); 139 | return true; 140 | } 141 | 142 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 143 | public boolean stopRecord(String tip) { 144 | // Log.w("lala","stopRecord: first "); 145 | 146 | if (!mIsRunning) { 147 | return false; 148 | } 149 | mIsRunning = false; 150 | // Log.w("lala","stopRecord middle"); 151 | 152 | try { 153 | mMediaRecorder.stop(); 154 | mMediaRecorder.reset(); 155 | mMediaRecorder = null; 156 | mVirtualDisplay.release(); 157 | mMediaProjection.stop(); 158 | 159 | // Log.w("lala","stopRecord "); 160 | 161 | }catch (Exception e){ 162 | e.printStackTrace(); 163 | mMediaRecorder.release(); 164 | mMediaRecorder = null; 165 | // Log.w("lala","stopRecord exception"); 166 | 167 | } 168 | 169 | 170 | mMediaProjection = null; 171 | 172 | mHandler.removeMessages(MSG_TYPE_COUNT_DOWN); 173 | ScreenUtil.stopRecord(tip); 174 | 175 | if (mRecordSeconds <= 2 ){ 176 | 177 | FileUtil.deleteSDFile(mRecordFilePath); 178 | }else { 179 | //通知系统图库更新 180 | FileUtil.fileScanVideo(this,mRecordFilePath,mRecordWidth,mRecordHeight,mRecordSeconds); 181 | } 182 | 183 | // mRecordFilePath = null; 184 | mRecordSeconds = 0; 185 | 186 | return true; 187 | } 188 | 189 | 190 | 191 | public void pauseRecord(){ 192 | if (mMediaRecorder != null ){ 193 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 194 | mMediaRecorder.pause(); 195 | } 196 | } 197 | 198 | } 199 | 200 | public void resumeRecord(){ 201 | if (mMediaRecorder != null ){ 202 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 203 | mMediaRecorder.resume(); 204 | } 205 | } 206 | } 207 | 208 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 209 | private void createVirtualDisplay() { 210 | mVirtualDisplay = mMediaProjection.createVirtualDisplay("MainScreen", mRecordWidth, mRecordHeight, mScreenDpi, 211 | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null); 212 | } 213 | 214 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 215 | private void setUpMediaRecorder() { 216 | 217 | mRecordFilePath = getSaveDirectory() + File.separator+ System.currentTimeMillis() + ".mp4"; 218 | if (mMediaRecorder == null){ 219 | mMediaRecorder = new MediaRecorder(); 220 | } 221 | mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 222 | mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); 223 | mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 224 | mMediaRecorder.setOutputFile( mRecordFilePath ); 225 | mMediaRecorder.setVideoSize(mRecordWidth, mRecordHeight); 226 | mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 227 | mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 228 | mMediaRecorder.setVideoEncodingBitRate((int) (mRecordWidth * mRecordHeight * 3.6)); 229 | mMediaRecorder.setVideoFrameRate(20); 230 | 231 | try { 232 | mMediaRecorder.prepare(); 233 | } catch (IOException e) { 234 | e.printStackTrace(); 235 | } 236 | } 237 | 238 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 239 | public void clearAll(){ 240 | if (mMediaProjection != null){ 241 | mMediaProjection.stop(); 242 | mMediaProjection = null; 243 | } 244 | } 245 | 246 | public String getRecordFilePath(){ 247 | return mRecordFilePath; 248 | } 249 | 250 | public String getSaveDirectory() { 251 | 252 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 253 | 254 | return Environment.getExternalStorageDirectory().getAbsolutePath(); 255 | } else { 256 | return null; 257 | } 258 | } 259 | 260 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 261 | @Override 262 | public boolean handleMessage(Message msg) { 263 | switch (msg.what){ 264 | 265 | case MSG_TYPE_COUNT_DOWN:{ 266 | 267 | String str = null; 268 | boolean enough = FileUtil.getSDFreeMemory() / (1024* 1024) < 4; 269 | if (enough){ 270 | //空间不足,停止录屏 271 | str = getString(R.string.record_space_tip); 272 | stopRecord(str); 273 | mRecordSeconds = 0; 274 | break; 275 | } 276 | 277 | mRecordSeconds++; 278 | int minute = 0, second = 0; 279 | if (mRecordSeconds >= 60 ){ 280 | minute = mRecordSeconds / 60; 281 | second = mRecordSeconds % 60; 282 | } else { 283 | second = mRecordSeconds; 284 | } 285 | ScreenUtil.onRecording("0"+minute+":"+ (second < 10 ? "0"+second :second+"") ); 286 | 287 | if (mRecordSeconds < 3 * 60 ){ 288 | mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN,1000); 289 | } else if (mRecordSeconds == 3 * 60 ){ 290 | str = getString(R.string.record_time_end_tip); 291 | stopRecord(str); 292 | mRecordSeconds = 0; 293 | } 294 | 295 | break; 296 | } 297 | } 298 | return true; 299 | } 300 | 301 | public class RecordBinder extends Binder { 302 | public ScreenRecordService getRecordService() { 303 | return ScreenRecordService.this; 304 | } 305 | } 306 | 307 | 308 | } 309 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/service/ScreenUtil.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.service; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.media.projection.MediaProjectionManager; 8 | import android.os.Build; 9 | import android.widget.Toast; 10 | 11 | 12 | import com.hani.coolcode.R; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by admin on 2018/3/28. 19 | */ 20 | 21 | public class ScreenUtil { 22 | 23 | 24 | private static ScreenRecordService s_ScreenRecordService; 25 | 26 | private static List s_RecordListener = new ArrayList<>(); 27 | 28 | private static List s_PageRecordListener = new ArrayList<>(); 29 | 30 | //true,录制结束的提示语正在显示 31 | public static boolean s_IsRecordingTipShowing = false; 32 | 33 | /** 34 | * 录屏功能 5.0+ 的手机才能使用 35 | * @return 36 | */ 37 | public static boolean isScreenRecordEnable(){ 38 | 39 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ; 40 | 41 | } 42 | 43 | 44 | public static void setScreenService(ScreenRecordService screenService){ 45 | s_ScreenRecordService = screenService; 46 | } 47 | 48 | public static void clear(){ 49 | if ( isScreenRecordEnable() && s_ScreenRecordService != null){ 50 | s_ScreenRecordService.clearAll(); 51 | s_ScreenRecordService = null; 52 | 53 | } 54 | 55 | if (s_RecordListener != null && s_RecordListener.size() > 0){ 56 | s_RecordListener.clear(); 57 | } 58 | 59 | if (s_PageRecordListener != null && s_PageRecordListener.size() > 0 ){ 60 | s_PageRecordListener.clear(); 61 | } 62 | } 63 | 64 | /** 65 | * 开始录制 66 | */ 67 | public static void startScreenRecord(Activity activity,int requestCode) { 68 | 69 | if (isScreenRecordEnable()){ 70 | 71 | if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){ 72 | 73 | if (!s_ScreenRecordService.isReady()){ 74 | 75 | MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity. 76 | getSystemService(Context.MEDIA_PROJECTION_SERVICE); 77 | if (mediaProjectionManager != null){ 78 | Intent intent = mediaProjectionManager.createScreenCaptureIntent(); 79 | PackageManager packageManager = activity.getPackageManager(); 80 | if (packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null){ 81 | //存在录屏授权的Activity 82 | activity.startActivityForResult(intent,requestCode); 83 | }else { 84 | Toast.makeText(activity,R.string.can_not_record_tip,Toast.LENGTH_SHORT).show(); 85 | } 86 | } 87 | 88 | } else { 89 | s_ScreenRecordService.startRecord(); 90 | 91 | } 92 | 93 | } 94 | } 95 | 96 | } 97 | 98 | /** 99 | * 获取用户允许录屏后,设置必要的数据 100 | * @param resultCode 101 | * @param resultData 102 | */ 103 | public static void setUpData(int resultCode,Intent resultData) throws Exception{ 104 | 105 | if (isScreenRecordEnable()){ 106 | 107 | if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){ 108 | s_ScreenRecordService.setResultData(resultCode,resultData); 109 | s_ScreenRecordService.startRecord(); 110 | 111 | } 112 | 113 | } 114 | } 115 | 116 | /** 117 | * 停止录制 118 | */ 119 | public static void stopScreenRecord(Context context){ 120 | if (isScreenRecordEnable()){ 121 | if (s_ScreenRecordService != null && s_ScreenRecordService.ismIsRunning()){ 122 | String str = context.getString(R.string.record_video_tip); 123 | s_ScreenRecordService.stopRecord(str); 124 | } 125 | } 126 | } 127 | 128 | /** 129 | * 获取录制后的文件地址 130 | * @return 131 | */ 132 | public static String getScreenRecordFilePath(){ 133 | 134 | if (isScreenRecordEnable() && s_ScreenRecordService!= null) { 135 | return s_ScreenRecordService.getRecordFilePath(); 136 | } 137 | return null; 138 | 139 | } 140 | 141 | /** 142 | * 判断当前是否在录制 143 | * @return 144 | */ 145 | public static boolean isCurrentRecording(){ 146 | if (isScreenRecordEnable() && s_ScreenRecordService!= null) { 147 | return s_ScreenRecordService.ismIsRunning(); 148 | } 149 | return false; 150 | } 151 | 152 | /** 153 | * true,录制结束的提示语正在显示 154 | * @return 155 | */ 156 | public static boolean isRecodingTipShow(){ 157 | return s_IsRecordingTipShowing; 158 | } 159 | 160 | public static void setRecordingStatus(boolean isShow){ 161 | s_IsRecordingTipShowing = isShow; 162 | } 163 | 164 | 165 | /** 166 | * 系统正在录屏,app 录屏会有冲突,清理掉一些数据 167 | */ 168 | public static void clearRecordElement(){ 169 | 170 | if (isScreenRecordEnable()){ 171 | if (s_ScreenRecordService != null ){ 172 | s_ScreenRecordService.clearRecordElement(); 173 | } 174 | } 175 | } 176 | 177 | public static void addRecordListener(RecordListener listener){ 178 | 179 | if (listener != null && !s_RecordListener.contains(listener)){ 180 | s_RecordListener.add(listener); 181 | } 182 | 183 | } 184 | 185 | public static void removeRecordListener(RecordListener listener){ 186 | if (listener != null && s_RecordListener.contains(listener)){ 187 | s_RecordListener.remove(listener); 188 | } 189 | } 190 | 191 | public static void addPageRecordListener( OnPageRecordListener listener){ 192 | 193 | if (listener != null && !s_PageRecordListener.contains(listener)){ 194 | s_PageRecordListener.add(listener); 195 | } 196 | } 197 | 198 | public static void removePageRecordListener( OnPageRecordListener listener){ 199 | 200 | if (listener != null && s_PageRecordListener.contains(listener)){ 201 | s_PageRecordListener.remove(listener); 202 | } 203 | } 204 | 205 | public static void onPageRecordStart(){ 206 | if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){ 207 | for (OnPageRecordListener listener : s_PageRecordListener){ 208 | listener.onStartRecord(); 209 | } 210 | } 211 | } 212 | 213 | 214 | public static void onPageRecordStop(){ 215 | if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){ 216 | for (OnPageRecordListener listener : s_PageRecordListener){ 217 | listener.onStopRecord(); 218 | } 219 | } 220 | } 221 | 222 | public static void onPageBeforeShowAnim(){ 223 | if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){ 224 | for (OnPageRecordListener listener : s_PageRecordListener){ 225 | listener.onBeforeShowAnim(); 226 | } 227 | } 228 | } 229 | 230 | public static void onPageAfterHideAnim(){ 231 | if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){ 232 | for (OnPageRecordListener listener : s_PageRecordListener){ 233 | listener.onAfterHideAnim(); 234 | } 235 | } 236 | } 237 | 238 | public static void startRecord(){ 239 | if (s_RecordListener.size() > 0 ){ 240 | for (RecordListener listener : s_RecordListener){ 241 | listener.onStartRecord(); 242 | } 243 | } 244 | } 245 | 246 | public static void pauseRecord(){ 247 | if (s_RecordListener.size() > 0 ){ 248 | for (RecordListener listener : s_RecordListener){ 249 | listener.onPauseRecord(); 250 | } 251 | } 252 | } 253 | 254 | public static void resumeRecord(){ 255 | if (s_RecordListener.size() > 0 ){ 256 | for (RecordListener listener : s_RecordListener){ 257 | listener.onResumeRecord(); 258 | } 259 | } 260 | } 261 | 262 | public static void onRecording(String timeTip){ 263 | if (s_RecordListener.size() > 0 ){ 264 | for (RecordListener listener : s_RecordListener){ 265 | listener.onRecording(timeTip); 266 | } 267 | } 268 | } 269 | 270 | public static void stopRecord(String stopTip){ 271 | if (s_RecordListener.size() > 0 ){ 272 | for (RecordListener listener : s_RecordListener){ 273 | listener.onStopRecord( stopTip); 274 | } 275 | } 276 | } 277 | 278 | public interface RecordListener{ 279 | 280 | 281 | void onStartRecord(); 282 | void onPauseRecord(); 283 | void onResumeRecord(); 284 | void onStopRecord(String stopTip); 285 | void onRecording(String timeTip); 286 | } 287 | 288 | 289 | public interface OnPageRecordListener { 290 | 291 | void onStartRecord(); 292 | void onStopRecord(); 293 | 294 | void onBeforeShowAnim(); 295 | void onAfterHideAnim(); 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/utils/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.utils; 2 | 3 | import android.app.Activity; 4 | import android.util.DisplayMetrics; 5 | import android.view.Display; 6 | 7 | /** 8 | * Created by Administrator on 2018/3/8 0008. 9 | */ 10 | 11 | public class CommonUtil { 12 | 13 | private static int mScreenWidth; 14 | private static int mScreenHeight; 15 | 16 | private static int mScreenDpi; 17 | 18 | public static void init(Activity activity){ 19 | 20 | Display display = activity.getWindowManager().getDefaultDisplay(); 21 | DisplayMetrics metrics = new DisplayMetrics(); 22 | display.getMetrics(metrics); 23 | mScreenWidth = metrics.widthPixels; 24 | mScreenHeight = metrics.heightPixels; 25 | mScreenDpi = metrics.densityDpi; 26 | } 27 | 28 | public static int getScreenWidth(){ 29 | return mScreenWidth; 30 | } 31 | 32 | public static int getScreenHeight(){ 33 | return mScreenHeight; 34 | } 35 | 36 | public static int getScreenDpi(){ 37 | return mScreenDpi; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.utils; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.media.MediaScannerConnection; 7 | import android.net.Uri; 8 | import android.os.Environment; 9 | import android.os.StatFs; 10 | import android.provider.MediaStore; 11 | import android.text.TextUtils; 12 | import android.util.Log; 13 | 14 | import java.io.File; 15 | 16 | public class FileUtil { 17 | 18 | /** 19 | * 删除SD卡中的文件或目录 20 | * 21 | * @param path 22 | * @return 23 | */ 24 | public static boolean deleteSDFile(String path) { 25 | return deleteSDFile(path, false); 26 | } 27 | 28 | /** 29 | * 删除SD卡中的文件或目录 30 | * 31 | * @param path 32 | * @param deleteParent true为删除父目录 33 | * @return 34 | */ 35 | public static boolean deleteSDFile(String path, boolean deleteParent) { 36 | if (TextUtils.isEmpty(path)) { 37 | return false; 38 | } 39 | 40 | File file = new File(path); 41 | if (!file.exists()) { 42 | //不存在 43 | return true; 44 | } 45 | return deleteFile(file, deleteParent); 46 | } 47 | 48 | /** 49 | * @param file 50 | * @param deleteParent true为删除父目录 51 | * @return 52 | */ 53 | public static boolean deleteFile(File file, boolean deleteParent) { 54 | boolean flag = false; 55 | if (file == null) { 56 | return flag; 57 | } 58 | if (file.isDirectory()) { 59 | //是文件夹 60 | File[] files = file.listFiles(); 61 | if (files.length > 0) { 62 | for (int i = 0; i < files.length; i++) { 63 | flag = deleteFile(files[i], true); 64 | if (!flag) { 65 | return flag; 66 | } 67 | } 68 | } 69 | if (deleteParent) { 70 | flag = file.delete(); 71 | } 72 | } else { 73 | flag = file.delete(); 74 | } 75 | file = null; 76 | return flag; 77 | } 78 | 79 | /** 80 | * 添加到媒体数据库 81 | * 82 | * @param context 上下文 83 | */ 84 | public static Uri fileScanVideo(Context context, String videoPath, int videoWidth, int videoHeight, 85 | int videoTime) { 86 | 87 | File file = new File(videoPath); 88 | if (file.exists()) { 89 | 90 | Uri uri = null; 91 | 92 | long size = file.length(); 93 | String fileName = file.getName(); 94 | long dateTaken = System.currentTimeMillis(); 95 | 96 | ContentValues values = new ContentValues(11); 97 | values.put(MediaStore.Video.Media.DATA, videoPath); // 路径; 98 | values.put(MediaStore.Video.Media.TITLE, fileName); // 标题; 99 | values.put(MediaStore.Video.Media.DURATION, videoTime * 1000); // 时长 100 | values.put(MediaStore.Video.Media.WIDTH, videoWidth); // 视频宽 101 | values.put(MediaStore.Video.Media.HEIGHT, videoHeight); // 视频高 102 | values.put(MediaStore.Video.Media.SIZE, size); // 视频大小; 103 | values.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken); // 插入时间; 104 | values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);// 文件名; 105 | values.put(MediaStore.Video.Media.DATE_MODIFIED, dateTaken / 1000);// 修改时间; 106 | values.put(MediaStore.Video.Media.DATE_ADDED, dateTaken / 1000); // 添加时间; 107 | values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); 108 | 109 | ContentResolver resolver = context.getContentResolver(); 110 | 111 | if (resolver != null) { 112 | try { 113 | uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | uri = null; 117 | } 118 | } 119 | 120 | if (uri == null) { 121 | MediaScannerConnection.scanFile(context, new String[]{videoPath}, new String[]{"video/*"}, new MediaScannerConnection.OnScanCompletedListener() { 122 | @Override 123 | public void onScanCompleted(String path, Uri uri) { 124 | 125 | } 126 | }); 127 | } 128 | 129 | return uri; 130 | } 131 | 132 | return null; 133 | } 134 | 135 | /** 136 | * SD卡存在并可以使用 137 | */ 138 | public static boolean isSDExists() { 139 | return Environment.getExternalStorageState().equals( 140 | Environment.MEDIA_MOUNTED); 141 | } 142 | 143 | /** 144 | * 获取SD卡的剩余容量,单位是Byte 145 | * 146 | * @return 147 | */ 148 | public static long getSDFreeMemory() { 149 | try { 150 | if (isSDExists()) { 151 | File pathFile = Environment.getExternalStorageDirectory(); 152 | // Retrieve overall information about the space on a filesystem. 153 | // This is a Wrapper for Unix statfs(). 154 | StatFs statfs = new StatFs(pathFile.getPath()); 155 | // 获取SDCard上每一个block的SIZE 156 | long nBlockSize = statfs.getBlockSize(); 157 | // 获取可供程序使用的Block的数量 158 | // long nAvailBlock = statfs.getAvailableBlocksLong(); 159 | long nAvailBlock = statfs.getAvailableBlocks(); 160 | // 计算SDCard剩余大小Byte 161 | long nSDFreeSize = nAvailBlock * nBlockSize; 162 | return nSDFreeSize; 163 | } 164 | } catch (Exception ex) { 165 | ex.printStackTrace(); 166 | } 167 | return 0; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/utils/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.text.TextUtils; 7 | import android.util.DisplayMetrics; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import java.io.File; 12 | import java.lang.reflect.Field; 13 | 14 | /** 15 | * Created by Administrator on 2018/3/12 0012. 16 | */ 17 | 18 | public class ImageUtil { 19 | 20 | public static void setPicToImageView(ImageView imageView, String imagePath){ 21 | 22 | BitmapFactory.Options opts = new BitmapFactory.Options(); 23 | 24 | opts.inJustDecodeBounds = true; 25 | BitmapFactory.decodeFile(imagePath, opts); 26 | 27 | ImageSize imageSize = getImageViewSize(imageView); 28 | 29 | opts.inSampleSize = caculateInSampleSize(opts,imageSize.width,imageSize.height); 30 | 31 | opts.inPurgeable = true; 32 | opts.inJustDecodeBounds = false; 33 | 34 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath, opts); 35 | imageView.setImageBitmap(bitmap); 36 | } 37 | 38 | 39 | public static void setPicToImageView(Context context, ImageView imageView, int resId){ 40 | 41 | BitmapFactory.Options opts = new BitmapFactory.Options(); 42 | opts.inJustDecodeBounds = true; 43 | BitmapFactory.decodeResource(context.getResources(),resId,opts); 44 | 45 | ImageSize imageSize = getImageViewSize(imageView); 46 | 47 | opts.inSampleSize = caculateInSampleSize(opts,imageSize.width,imageSize.height); 48 | 49 | opts.inJustDecodeBounds = false; 50 | 51 | Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resId,opts); 52 | imageView.setImageBitmap(bitmap); 53 | 54 | } 55 | 56 | /** 57 | * 根据需求的宽和高以及图片实际的宽和高计算SampleSize 58 | * 59 | * @param options 60 | * @param reqWidth 61 | * @param reqHeight 62 | * @return 63 | */ 64 | public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, 65 | int reqHeight) 66 | { 67 | int width = options.outWidth; 68 | int height = options.outHeight; 69 | 70 | int inSampleSize = 1; 71 | 72 | if (width > reqWidth || height > reqHeight) 73 | { 74 | int widthRadio = Math.round(width * 1.0f / reqWidth); 75 | int heightRadio = Math.round(height * 1.0f / reqHeight); 76 | 77 | inSampleSize = Math.max(widthRadio, heightRadio); 78 | } 79 | 80 | return inSampleSize; 81 | } 82 | 83 | 84 | 85 | 86 | /** 87 | * 根据ImageView获适当的压缩的宽和高 88 | * 89 | * @param imageView 90 | * @return 91 | */ 92 | public static ImageSize getImageViewSize(ImageView imageView) 93 | { 94 | 95 | ImageSize imageSize = new ImageSize(); 96 | DisplayMetrics displayMetrics = imageView.getContext().getResources() 97 | .getDisplayMetrics(); 98 | 99 | 100 | ViewGroup.LayoutParams lp = imageView.getLayoutParams(); 101 | 102 | int width = imageView.getWidth();// 获取imageview的实际宽度 103 | if (width <= 0) 104 | { 105 | width = lp.width;// 获取imageview在layout中声明的宽度 106 | } 107 | if (width <= 0) 108 | { 109 | //width = imageView.getMaxWidth();// 检查最大值 110 | width = getImageViewFieldValue(imageView, "mMaxWidth"); 111 | } 112 | if (width <= 0) 113 | { 114 | width = displayMetrics.widthPixels; 115 | } 116 | 117 | int height = imageView.getHeight();// 获取imageview的实际高度 118 | if (height <= 0) 119 | { 120 | height = lp.height;// 获取imageview在layout中声明的宽度 121 | } 122 | if (height <= 0) 123 | { 124 | height = getImageViewFieldValue(imageView, "mMaxHeight");// 检查最大值 125 | } 126 | if (height <= 0) 127 | { 128 | height = displayMetrics.heightPixels; 129 | } 130 | imageSize.width = width; 131 | imageSize.height = height; 132 | 133 | /*Log.w("screen","imageSize width: "+imageSize.width); 134 | Log.w("screen","imageSize height: "+imageSize.height); 135 | 136 | Log.w("screen","screen width : "+ ShareData.m_screenWidth); 137 | Log.w("screen","screen height : "+ ShareData.m_screenHeight); 138 | 139 | Log.w("screen","displayMetrics.widthPixels : "+displayMetrics.widthPixels); 140 | Log.w("screen","displayMetrics.heightPixels : "+displayMetrics.heightPixels);*/ 141 | 142 | return imageSize; 143 | } 144 | 145 | public static class ImageSize 146 | { 147 | int width; 148 | int height; 149 | } 150 | 151 | /** 152 | * 通过反射获取imageview的某个属性值 153 | * 154 | * @param object 155 | * @param fieldName 156 | * @return 157 | */ 158 | private static int getImageViewFieldValue(Object object, String fieldName) 159 | { 160 | int value = 0; 161 | try 162 | { 163 | Field field = ImageView.class.getDeclaredField(fieldName); 164 | field.setAccessible(true); 165 | int fieldValue = field.getInt(object); 166 | if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) 167 | { 168 | value = fieldValue; 169 | } 170 | } catch (Exception e) 171 | { 172 | } 173 | return value; 174 | 175 | } 176 | 177 | /** 178 | * 根据要求的宽高,从本地路径得到bitmap 179 | * @param picPath 180 | * @param width 181 | * @param height 182 | * @return 183 | */ 184 | public static Bitmap createBitmap(String picPath, int width, int height){ 185 | if(!TextUtils.isEmpty(picPath)){ 186 | BitmapFactory.Options opts = new BitmapFactory.Options(); 187 | 188 | opts.inJustDecodeBounds = true; 189 | BitmapFactory.decodeFile(picPath, opts); 190 | 191 | opts.inSampleSize = caculateInSampleSize(opts,width,height); 192 | 193 | opts.inJustDecodeBounds = false; 194 | 195 | 196 | Bitmap bitmap = BitmapFactory.decodeFile(picPath, opts); 197 | return bitmap; 198 | } 199 | return null; 200 | } 201 | 202 | public static Bitmap createBitmap(Context context, int resId, int width, int height){ 203 | if( resId != 0){ 204 | BitmapFactory.Options opts = new BitmapFactory.Options(); 205 | 206 | opts.inJustDecodeBounds = true; 207 | BitmapFactory.decodeResource(context.getResources(),resId,opts); 208 | 209 | opts.inSampleSize = caculateInSampleSize(opts,width,height); 210 | 211 | opts.inJustDecodeBounds = false; 212 | 213 | 214 | Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resId,opts); 215 | return bitmap; 216 | } 217 | return null; 218 | } 219 | 220 | public static Bitmap getBitmap(Context context, Object path, int width, int height){ 221 | 222 | Bitmap bitmap = null; 223 | 224 | if (path instanceof String){ 225 | bitmap = createBitmap((String) path,width,height); 226 | 227 | 228 | } else if (path instanceof Integer){ 229 | if (context != null ){ 230 | bitmap = createBitmap(context, (Integer) path,width,height); 231 | } 232 | } 233 | return bitmap; 234 | } 235 | 236 | /** 237 | * 得到图片的尺寸 238 | * @param picPath 239 | * @return size[0] width; size[1] height 240 | */ 241 | public static int[] getPicSize(String picPath){ 242 | 243 | int[] size = new int[]{0,0}; 244 | File file = new File(picPath); 245 | if(!TextUtils.isEmpty(picPath) && file.exists() && file.isFile() ){ 246 | BitmapFactory.Options opts = new BitmapFactory.Options(); 247 | 248 | opts.inJustDecodeBounds = true; 249 | BitmapFactory.decodeFile(picPath, opts); 250 | size[0] = opts.outWidth; 251 | size[1] = opts.outHeight; 252 | 253 | return size; 254 | } 255 | return size; 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/utils/PermissionUtils.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.utils; 2 | 3 | import android.Manifest; 4 | import android.content.pm.PackageManager; 5 | import android.os.Build; 6 | import android.support.v4.app.ActivityCompat; 7 | import android.support.v4.content.ContextCompat; 8 | import android.support.v7.app.AppCompatActivity; 9 | 10 | /** 11 | * 动态申请权限 12 | * 可以在activity中增加如果权限被拒绝后的弹窗,在onRequestPermissionsResult中判断状态 13 | * 14 | * @author lixiao 15 | * @since 2017-10-25 00:00 16 | */ 17 | public class PermissionUtils { 18 | /** 19 | * 获取打开摄像机的权限,录音,文件读写 20 | * 21 | * @param activity 22 | */ 23 | public static void checkPermission(AppCompatActivity activity) { 24 | if (Build.VERSION.SDK_INT >= 23) { 25 | int checkPermission = 26 | ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) 27 | + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE) 28 | + ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) 29 | + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE); 30 | if (checkPermission != PackageManager.PERMISSION_GRANTED) { 31 | //动态申请 32 | ActivityCompat.requestPermissions(activity, new String[]{ 33 | Manifest.permission.RECORD_AUDIO, 34 | Manifest.permission.READ_PHONE_STATE, 35 | Manifest.permission.READ_EXTERNAL_STORAGE, 36 | Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123); 37 | return; 38 | } else { 39 | return; 40 | } 41 | } 42 | return; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/hani/coolcode/utils/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | /** 7 | * Created by admin on 2017/5/19. 8 | */ 9 | 10 | public class ToastUtil { 11 | 12 | private static Toast mToast; 13 | 14 | public static void show(Context context,String msg){ 15 | if(mToast == null){ 16 | mToast = Toast.makeText(context,msg,Toast.LENGTH_SHORT); 17 | } 18 | else { 19 | mToast.setText(msg); 20 | } 21 | mToast.show(); 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading08.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading09.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading10.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading11.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading12.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading13.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading14.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading15.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading16.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading17.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading18.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading19.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading20.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading21.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading22.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading23.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading24.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading25.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading26.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading27.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading28.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading29.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading30.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading31.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading32.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading33.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading34.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading35.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading36.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading37.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading38.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading39.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading40.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading41.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading42.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading43.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading44.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading45.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading46.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading47.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading48.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading49.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading50.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading51.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading52.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading53.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading54.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading55.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading56.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading57.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading58.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading59.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading60.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading61.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading62.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading63.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading64.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading65.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading66.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading67.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading68.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading69.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading69.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading70.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading71.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading72.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading73.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading74.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading74.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loading75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/drawable-xhdpi/loading75.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/animation_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 20 | 21 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/inner_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/screen_record_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 19 | 20 | 27 | 28 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #42e69f 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CoolCode 3 | 停止录制 4 | 暂时无法录制 5 | 存储空间不足 6 | 录制已到限定时长 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/hani/coolcode/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hani.coolcode; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.0' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanilala/CoolCode/b4b921e4fa4cfcd6b170d6da8b5e923fee5a0f8f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon May 14 21:12:30 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------