Просмотр исходного кода

添加5.0以上可以截图的功能

zengjiebin лет назад: 7
Родитель
Сommit
73af3c1afb

+ 5 - 2
app/src/main/AndroidManifest.xml

@@ -111,7 +111,11 @@
         <service
             android:name=".service.FloatService"
             android:enabled="true"
-            android:exported="true"></service>
+            android:exported="true"/>
+        <service
+            android:name=".service.FloatShotScreenService"
+            android:enabled="true"
+            android:exported="true"/>
 
         <provider
             android:name=".provider.SheepFileProvider"
@@ -374,7 +378,6 @@
             android:name="com.sheep.gamegroup.view.activity.ActXiaomiGame"
             android:screenOrientation="portrait" />
 
-
         <!--友盟start-->
         <meta-data
             android:name="UMENG_APPKEY"

+ 0 - 62
app/src/main/java/com/kfzs/duanduan/ActMain.java

@@ -1,25 +1,17 @@
 package com.kfzs.duanduan;
 
-import android.Manifest;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.Toast;
 
 import com.kfzs.appstore.utils.restful.KFZSNetwork;
 import com.kfzs.duanduan.event.BigEvent;
 import com.kfzs.duanduan.react.TabsHelper;
 import com.kfzs.duanduan.utils.dlg.HelperUtils;
 import com.kfzs.duanduan.view.DialogStorageLow;
-import com.mdad.sdk.mdsdk.AdManager;
 import com.sheep.gamegroup.absBase.BaseActivity;
 import com.sheep.gamegroup.model.entity.Container;
-import com.sheep.gamegroup.util.Jump2View;
 import com.sheep.gamegroup.util.UMConfigUtils;
 import com.sheep.jiuyan.samllsheep.R;
 import com.umeng.socialize.UMShareAPI;
@@ -27,9 +19,6 @@ import com.umeng.socialize.UMShareAPI;
 import org.greenrobot.eventbus.EventBus;
 import org.greenrobot.eventbus.Subscribe;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import rx.functions.Action1;
@@ -42,13 +31,11 @@ public class ActMain extends BaseActivity {
     LinearLayout other_container;
 
     public final static String INTENT_GAME_ID = "INTEN_GAME_ID";
-    public final static String INTENT_IS_FROM_LOGIN = "INTENT_IS_FROM_LOGIN";
 
 
     private ImageView mImgDot;//下载按钮的小红点
 
 
-    private final static int INTENT_GET_PERMISSION = 1;
 
     public TabsHelper tabsHelper;
 
@@ -61,7 +48,6 @@ public class ActMain extends BaseActivity {
     public void initView() {
         KFZSApp.actMain = this;
         tabsHelper = new TabsHelper();
-        getSA();//6.0以上获取必要权限
         HelperUtils.init();//初始化屏幕的高,density等
         ButterKnife.bind(this);
         EventBus.getDefault().register(this);
@@ -95,54 +81,6 @@ public class ActMain extends BaseActivity {
     }
 
 
-
-    /**
-     * 申请读写权限6.0
-     */
-    private void getSA() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-            return;
-        }
-        List<String> sa = new ArrayList<>();
-        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
-                != PackageManager.PERMISSION_GRANTED) {
-            sa.add(Manifest.permission.READ_PHONE_STATE);
-        }
-        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
-                != PackageManager.PERMISSION_GRANTED) {
-            sa.add(Manifest.permission.READ_EXTERNAL_STORAGE);
-        }
-        if (sa.size() < 1) {//如果都已经授权了,不能空列表去请求,否则报异常
-            return;
-        }
-        ActivityCompat.requestPermissions(this, sa.toArray(new String[]{}), INTENT_GET_PERMISSION);
-    }
-
-
-    /**
-     * 权限申请的回调
-     *
-     * @param requestCode
-     * @param permissions
-     * @param grantResults
-     */
-    @Override
-    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-        if (requestCode == INTENT_GET_PERMISSION) {
-            boolean isOk = true;
-            for (int result : grantResults) {
-                if (result == PackageManager.PERMISSION_DENIED) {
-                    isOk = false;
-                    break;//只要有一个拒绝,就退出并提示
-                }
-            }
-            if (!isOk) {
-                Toast.makeText(ActMain.this, "权限获取失败,部分功能可能无法正常工作。", Toast.LENGTH_SHORT).show();
-            }
-        }
-        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-    }
-
     private Container<Action1<Integer>> container = new Container<>();
 
     public Container<Action1<Integer>> getContainer() {

+ 3 - 0
app/src/main/java/com/kfzs/duanduan/KFZSApp.java

@@ -15,6 +15,7 @@ import com.sheep.gamegroup.util.ActivityManager;
 import com.sheep.jiuyan.samllsheep.BuildConfig;
 import com.sheep.jiuyan.samllsheep.service.DownloadService;
 import com.sheep.jiuyan.samllsheep.service.FloatService;
+import com.sheep.jiuyan.samllsheep.service.FloatShotScreenService;
 import com.sheep.jiuyan.samllsheep.utils.G;
 
 
@@ -76,6 +77,7 @@ public class KFZSApp extends MultiDexApplication {
         KFZSNetwork.init(application);
         DisplayMetrics metric = getResources().getDisplayMetrics();
         G.DENSITY = metric.density;
+        G.DENSITY_DPI = metric.densityDpi;
         boolean isHeightBig = metric.heightPixels > metric.widthPixels;
         G.HEIGHT = isHeightBig ? metric.heightPixels : metric.widthPixels;
         G.WIDTH = isHeightBig ? metric.widthPixels : metric.heightPixels;
@@ -99,6 +101,7 @@ public class KFZSApp extends MultiDexApplication {
             Aria.download(this).stopAllTask();
             stopService(new Intent(this, DownloadService.class));
             stopService(new Intent(this, FloatService.class));
+            stopService(new Intent(this, FloatShotScreenService.class));
             ActivityManager.getInstance().finishAllActivity();
         } catch (Exception e) {
             Log.e(TAG, "quit error" + e.getMessage() + "\n" + e.getCause());

+ 1 - 1
app/src/main/java/com/sheep/gamegroup/model/entity/UserEntity.java

@@ -318,6 +318,6 @@ public class UserEntity implements Serializable {
     }
     //测试服用测试分享链接,正式服用正式的
     public String getShareLink(){
-        return TestUtil.isTest() ? "http://10.8.210.230:8902/share.html?invitation_code="+getInvitation_code(): getShare_link();
+        return TestUtil.isSheep() ? getShare_link() : "http://10.8.210.230:8902/share.html?invitation_code="+getInvitation_code();
     }
 }

+ 84 - 0
app/src/main/java/com/sheep/gamegroup/util/DataUtil.java

@@ -1,5 +1,9 @@
 package com.sheep.gamegroup.util;
 
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.media.projection.MediaProjectionManager;
 import android.text.TextUtils;
 
 import com.alibaba.fastjson.JSON;
@@ -8,12 +12,22 @@ import com.sheep.gamegroup.model.entity.BaseMessage;
 import com.sheep.gamegroup.model.entity.UserEntity;
 import com.sheep.jiuyan.samllsheep.BuildConfig;
 import com.sheep.jiuyan.samllsheep.SheepApp;
+import com.sheep.jiuyan.samllsheep.service.FloatShotScreenService;
+import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.SpUtils;
 
 import org.afinal.simplecache.ACache;
 import org.afinal.simplecache.ApiKey;
 
+import java.io.File;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import rx.functions.Action1;
+
+import static android.app.Activity.RESULT_OK;
 
 /**
  * Created by realicing on 2018/7/27.
@@ -232,5 +246,75 @@ public class DataUtil {
     public void setTaskListChanged(){
         tagList.clear();
     }
+
     //-----------------------------------------进行任务部分-----------------------------------------------------结束
+
+    //-----------------------------------------其它数据部分-----------------------------------------------------开始
+    private Map<String, Object> objectMap = new HashMap<>();
+    /**
+     * 存放共享数据
+     * @param key
+     * @param data
+     */
+    public void putData(String key, Object data) {
+        objectMap.put(key, data);
+    }
+    /**
+     * 获取共享数据并删除
+     * @param key
+     */
+    public Object getData(String key) {
+        if(objectMap.containsKey(key)) {
+            return objectMap.remove(key);
+        }
+        return null;
+    }
+
+    /**
+     * 截图路径
+     * @return
+     */
+    public File getScreenShotsFile() {
+        //TODO 这里还差个包名
+        return new File(SheepApp.getInstance().getDir("ScreenShots", Context.MODE_PRIVATE), String.format(Locale.CHINA, "%s.png", TimeUtil.getDate("yyyy-MM-dd-hh-mm-ss")));
+    }
+    /**
+     * 截图目录
+     * @return
+     */
+    public File getScreenShotsDir() {
+        return SheepApp.getInstance().getDir("ScreenShots", Context.MODE_PRIVATE);
+    }
+
+    //-----------------------------------------其它数据部分-----------------------------------------------------结束
+
+    public static final int REQUEST_MEDIA_PROJECTION = 18;
+    public static final String REQUEST_CAPTURE_PERMISSION = "requestCapturePermission";//获取录屏权限
+
+    private Action1<Integer> action1;
+    public void requestCapturePermission(Activity activity, Action1<Integer> action1) {
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+            this.action1 = action1;
+            //5.0 之后才允许使用屏幕截图
+            MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
+            if (mediaProjectionManager != null) {
+                activity.startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
+                return;
+            }
+        }
+        G.showToast("您的系统版本过低,暂不支持该功能");
+    }
+
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            case REQUEST_MEDIA_PROJECTION:
+                if (resultCode == RESULT_OK && data != null) {
+                    DataUtil.getInstance().putData(REQUEST_CAPTURE_PERMISSION, data);
+                    if(action1 != null)
+                        action1.call(0);
+                }
+                break;
+        }
+
+    }
 }

+ 362 - 0
app/src/main/java/com/sheep/gamegroup/util/GlobalScreenShot.java

@@ -0,0 +1,362 @@
+package com.sheep.gamegroup.util;
+
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.media.MediaActionSound;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.sheep.jiuyan.samllsheep.R;
+
+
+/**
+ * TODO: - Performance when over gl surfaces? Ie. Gallery - what do we say in the Toast? Which icon
+ * do we get if the user uses another type of gallery?
+ */
+public class GlobalScreenShot {
+  private static final String TAG = "GlobalScreenshot";
+
+  private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
+  private static final int SCREENSHOT_DROP_IN_DURATION = 430;
+  private static final int SCREENSHOT_DROP_OUT_DELAY = 500;
+  private static final int SCREENSHOT_DROP_OUT_DURATION = 430;
+  private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;
+  private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;
+  private static final float BACKGROUND_ALPHA = 0.5f;
+  private static final float SCREENSHOT_SCALE = 1f;
+  private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;
+  private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
+  private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
+  private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
+
+  private Context mContext;
+  private WindowManager mWindowManager;
+  private WindowManager.LayoutParams mWindowLayoutParams;
+  private Display mDisplay;
+  private DisplayMetrics mDisplayMetrics;
+
+  private Bitmap mScreenBitmap;
+  private View mScreenshotLayout;
+  private ImageView mBackgroundView;
+  private ImageView mScreenshotView;
+  private ImageView mScreenshotFlash;
+
+  private AnimatorSet mScreenshotAnimation;
+
+  private float mBgPadding;
+  private float mBgPaddingScale;
+
+  private MediaActionSound mCameraSound;
+
+
+  private onScreenShotListener mOnScreenShotListener;
+
+  /**
+   * @param context everything needs a context :(
+   */
+  public GlobalScreenShot(Context context) {
+    Resources r = context.getResources();
+    mContext = context;
+    LayoutInflater layoutInflater = (LayoutInflater)
+        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+    // Inflate the screenshot layout
+    mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
+    mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+    mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
+    mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
+    mScreenshotLayout.setFocusable(true);
+    mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
+      @Override
+      public boolean onTouch(View v, MotionEvent event) {
+        // Intercept and ignore all touch events
+        return true;
+      }
+    });
+
+    // Setup the window that we are going to use
+    mWindowLayoutParams = new WindowManager.LayoutParams(
+        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
+        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
+        WindowManager.LayoutParams.FLAG_FULLSCREEN
+            | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+        PixelFormat.TRANSLUCENT);
+    mWindowLayoutParams.setTitle("ScreenshotAnimation");
+    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+    mDisplay = mWindowManager.getDefaultDisplay();
+    mDisplayMetrics = new DisplayMetrics();
+    mDisplay.getRealMetrics(mDisplayMetrics);
+
+    // Scale has to account for both sides of the bg
+    mBgPadding = (float) r.getDimensionPixelSize(R.dimen.content_padding_1);
+    mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
+
+    // Setup the Camera shutter sound
+    mCameraSound = new MediaActionSound();
+    mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+  }
+
+
+  /**
+   * Takes a screenshot of the current display and shows an animation.
+   */
+  public void takeScreenshot(Bitmap bitmap, onScreenShotListener onScreenShotListener, boolean statusBarVisible, boolean navBarVisible) {
+    // Take the screenshot
+    mScreenBitmap = bitmap;
+    this.mOnScreenShotListener = onScreenShotListener;
+
+    if (mOnScreenShotListener != null) {
+      mOnScreenShotListener.onStartShot();
+    }
+
+    if (mScreenBitmap == null) {
+      notifyScreenshotError(mContext);
+      return;
+    }
+
+    // Optimizations
+    mScreenBitmap.setHasAlpha(false);
+    mScreenBitmap.prepareToDraw();
+
+    // Start the post-screenshot animation
+    startAnimation(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
+        statusBarVisible, navBarVisible);
+  }
+
+
+  /**
+   * Starts the animation after taking the screenshot
+   */
+  private void startAnimation(int w, int h, boolean statusBarVisible,
+                              boolean navBarVisible) {
+    // Add the view for the animation
+    mScreenshotView.setImageBitmap(mScreenBitmap);
+    mScreenshotLayout.requestFocus();
+
+    // Setup the animation with the screenshot just taken
+    if (mScreenshotAnimation != null) {
+      mScreenshotAnimation.end();
+      mScreenshotAnimation.removeAllListeners();
+    }
+
+    mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+    ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
+    ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
+        statusBarVisible, navBarVisible);
+    mScreenshotAnimation = new AnimatorSet();
+    mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
+    mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        // Save the screenshot once we have a bit of time now
+        saveScreenshotInWorkerThread();
+        mWindowManager.removeView(mScreenshotLayout);
+
+        // Clear any references to the bitmap
+        mScreenBitmap = null;
+        mScreenshotView.setImageBitmap(null);
+
+      }
+    });
+    mScreenshotLayout.post(new Runnable() {
+      @Override
+      public void run() {
+        // Play the shutter sound to notify that we've taken a screenshot
+        mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+
+        mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mScreenshotView.buildLayer();
+        mScreenshotAnimation.start();
+      }
+    });
+  }
+
+  private ValueAnimator createScreenshotDropInAnimation() {
+    final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
+        / SCREENSHOT_DROP_IN_DURATION);
+    final float flashDurationPct = 2f * flashPeakDurationPct;
+    final Interpolator flashAlphaInterpolator = new Interpolator() {
+      @Override
+      public float getInterpolation(float x) {
+        // Flash the flash view in and out quickly
+        if (x <= flashDurationPct) {
+          return (float) Math.sin(Math.PI * (x / flashDurationPct));
+        }
+        return 0;
+      }
+    };
+    final Interpolator scaleInterpolator = new Interpolator() {
+      @Override
+      public float getInterpolation(float x) {
+        // We start scaling when the flash is at it's peak
+        if (x < flashPeakDurationPct) {
+          return 0;
+        }
+        return (x - flashDurationPct) / (1f - flashDurationPct);
+      }
+    };
+    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+    anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
+    anim.addListener(new AnimatorListenerAdapter() {
+      @Override
+      public void onAnimationStart(Animator animation) {
+        mBackgroundView.setAlpha(0f);
+        mBackgroundView.setVisibility(View.VISIBLE);
+        mScreenshotView.setAlpha(0f);
+        mScreenshotView.setTranslationX(0f);
+        mScreenshotView.setTranslationY(0f);
+        mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
+        mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
+        mScreenshotView.setVisibility(View.VISIBLE);
+        mScreenshotFlash.setAlpha(0f);
+        mScreenshotFlash.setVisibility(View.VISIBLE);
+      }
+
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        mScreenshotFlash.setVisibility(View.GONE);
+      }
+    });
+    anim.addUpdateListener(new AnimatorUpdateListener() {
+      @Override
+      public void onAnimationUpdate(ValueAnimator animation) {
+        float t = (Float) animation.getAnimatedValue();
+        float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
+            - scaleInterpolator.getInterpolation(t)
+            * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
+        mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
+        mScreenshotView.setAlpha(t);
+        mScreenshotView.setScaleX(scaleT);
+        mScreenshotView.setScaleY(scaleT);
+        mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));
+      }
+    });
+    return anim;
+  }
+
+  private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
+                                                         boolean navBarVisible) {
+    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+    anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
+    anim.addListener(new AnimatorListenerAdapter() {
+      @Override
+      public void onAnimationEnd(Animator animation) {
+        mBackgroundView.setVisibility(View.GONE);
+        mScreenshotView.setVisibility(View.GONE);
+        mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+      }
+    });
+
+    if (!statusBarVisible || !navBarVisible) {
+      // There is no status bar/nav bar, so just fade the screenshot away in place
+      anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);
+      anim.addUpdateListener(new AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+          float t = (Float) animation.getAnimatedValue();
+          float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
+              - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
+          mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+          mScreenshotView.setAlpha(1f - t);
+          mScreenshotView.setScaleX(scaleT);
+          mScreenshotView.setScaleY(scaleT);
+        }
+      });
+    } else {
+      // In the case where there is a status bar, animate to the origin of the bar (top-left)
+      final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION
+          / SCREENSHOT_DROP_OUT_DURATION;
+      final Interpolator scaleInterpolator = new Interpolator() {
+        @Override
+        public float getInterpolation(float x) {
+          if (x < scaleDurationPct) {
+            // Decelerate, and scale the input accordingly
+            return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
+          }
+          return 1f;
+        }
+      };
+
+      // Determine the bounds of how to scale
+      float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
+      float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
+      final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
+      final PointF finalPos = new PointF(
+          -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
+          -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
+
+      // Animate the screenshot to the status bar
+      anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
+      anim.addUpdateListener(new AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+          float t = (Float) animation.getAnimatedValue();
+          float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
+              - scaleInterpolator.getInterpolation(t)
+              * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
+          mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+          mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
+          mScreenshotView.setScaleX(scaleT);
+          mScreenshotView.setScaleY(scaleT);
+          mScreenshotView.setTranslationX(t * finalPos.x);
+          mScreenshotView.setTranslationY(t * finalPos.y);
+        }
+      });
+    }
+    return anim;
+  }
+
+  private void notifyScreenshotError(Context context) {
+    if (mOnScreenShotListener != null) {
+      mOnScreenShotListener.onFinishShot(false);
+    }
+  }
+
+  private void saveScreenshotInWorkerThread() {
+    if (mOnScreenShotListener != null) {
+      mOnScreenShotListener.onFinishShot(true);
+    }
+  }
+
+
+  public interface onScreenShotListener {
+
+    void onStartShot();
+
+    void onFinishShot(boolean success);
+  }
+}

+ 25 - 0
app/src/main/java/com/sheep/gamegroup/util/Jump2View.java

@@ -99,12 +99,14 @@ import com.sheep.jiuyan.samllsheep.BuildConfig;
 import com.sheep.jiuyan.samllsheep.R;
 import com.sheep.jiuyan.samllsheep.SheepApp;
 import com.sheep.jiuyan.samllsheep.service.FloatService;
+import com.sheep.jiuyan.samllsheep.service.FloatShotScreenService;
 import com.sheep.jiuyan.samllsheep.utils.G;
 import com.sheep.jiuyan.samllsheep.utils.SpUtils;
 
 import org.afinal.simplecache.ACache;
 import org.xutils.ex.DbException;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -955,6 +957,20 @@ public class Jump2View {
                     .start(activity);
         }
     }
+    /**
+     * 显示多张图片
+     * @param context
+     * @param position
+     * @param files
+     */
+    public void showImgFiles(Context context, int position, File...files) {
+        showImgList(context, position, ListUtil.asList(new ListUtil.CallBack<File, String>() {
+            @Override
+            public String call(File file) {
+                return file.getAbsolutePath();
+            }
+        }, files));
+    }
 
 
 
@@ -968,6 +984,15 @@ public class Jump2View {
         intent.putExtra("isShow", isShow);
         context.startService(intent);
     }
+    /**
+     * 启动小绵羊悬浮窗
+     * @param context
+     */
+    public void startShotScreenFloat(Context context, boolean isShow) {
+        Intent intent = new Intent(context, FloatShotScreenService.class);
+        intent.putExtra("isShow", isShow);
+        context.startService(intent);
+    }
 
 
     /**

+ 9 - 0
app/src/main/java/com/sheep/gamegroup/util/ListUtil.java

@@ -86,6 +86,15 @@ public class ListUtil {
         Collections.addAll(list, items);
         return list;
     }
+    @SafeVarargs
+    public static <T,R> ArrayList<R> asList(CallBack<T, R> callBack, T...items) {
+        ArrayList<R> list = emptyList();
+        for (T t : items) {
+            R r = callBack.call(t);
+            list.add(r);
+        }
+        return list;
+    }
 
     public static <T> List<T> removeItem(List<T> list, CallBack<T, Boolean> callBack) {
         if(isEmpty(list)){

+ 13 - 1
app/src/main/java/com/sheep/gamegroup/util/TestUtil.java

@@ -46,6 +46,7 @@ import java.io.File;
 import java.util.List;
 import java.util.Locale;
 
+import me.iwf.photopicker.PhotoPicker;
 import rx.android.schedulers.AndroidSchedulers;
 import rx.functions.Action1;
 import rx.schedulers.Schedulers;
@@ -282,7 +283,8 @@ public class TestUtil {
      * @param activity
      */
     public static void test(final Activity activity) {
-        final String[] items = {"小米游戏","复制token","复制imsi","复制打点数据","测试可用金额","测试定位信息","测试apk的渠道","幂动科技","游戏搜索","游戏帐号","游戏代充","尝试开启第三方应用使用情况","测试代理页面","第三方应用使用情况",
+        final String[] items = {"复制token","复制打点数据","查看截图","复制imsi","小米游戏","测试可用金额","测试定位信息","测试apk的渠道","幂动科技","游戏搜索",
+                "游戏帐号","游戏代充","尝试开启第三方应用使用情况","测试代理页面","第三方应用使用情况",
                 "开启第三方应用使用情况","h5跳转","新手对话框","md5","空间不足提示框",
                 "显示已经安装应用列表","复制faq地址","复制代理地址","复制世界杯地址","任务游戏列表","世界杯活动","交通银行信用卡测试",
                 "浦发银行信用卡测试", "测试游戏模块","打卡成功提示","定向货币详情","进入绑定身份认证界面时的提示","提交身份认证时的提示", "检查标签",
@@ -293,6 +295,16 @@ public class TestUtil {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         switch (items[which]) {
+                            case "查看截图":
+                                File dir = DataUtil.getInstance().getScreenShotsDir();
+                                if(dir.exists()) {
+                                    G.showToast("截图个数为:" + dir.list().length);
+                                } else {
+                                    G.showToast("截图目录不存在");
+                                }
+                                if(dir.list().length > 0)
+                                    Jump2View.getInstance().showImgFiles(activity, 0, dir.listFiles());
+                                break;
                             case "小米游戏":
                                 Jump2View.getInstance().goXiaomiGameList(activity, null);
                                 break;

+ 4 - 5
app/src/main/java/com/sheep/gamegroup/util/TimeUtil.java

@@ -36,7 +36,7 @@ public class TimeUtil {
     public static String[] getCalendarShowTime(long paramLong)
     {
         String[] localObject;
-        String str = new SimpleDateFormat("yyyy:MM:dd", Locale.ENGLISH).format(new Date(paramLong));
+        String str = new SimpleDateFormat("yyyy:MM:dd", Locale.CHINA).format(new Date(paramLong));
         try
         {
             String[] arrayOfString = str.split(":");
@@ -63,15 +63,14 @@ public class TimeUtil {
         }
         return null;
     }
-    public static String getDate(String formate){
-        String str = new SimpleDateFormat(formate, Locale.ENGLISH).format(new Date());
-        return str;
+    public static String getDate(String format){
+        return new SimpleDateFormat(format, Locale.CHINA).format(new Date());
     }
     public static String getDate(String formate, long paramLong){
         Calendar c = Calendar.getInstance();
         c.setTimeInMillis(paramLong*1000);
         Date date = c.getTime();
-        String str = new SimpleDateFormat(formate, Locale.ENGLISH).format(date);
+        String str = new SimpleDateFormat(formate, Locale.CHINA).format(date);
         return str;
     }
 

+ 32 - 1
app/src/main/java/com/sheep/gamegroup/view/activity/ActWeb.java

@@ -285,8 +285,20 @@ public class ActWeb extends BaseCompatActivity {
             });
         }
 
+        /**
+         * 是否响应返回键
+         */
         @JavascriptInterface
-        public void setCanGoBack() {
+        public boolean isResponseBack() {
+            return responseBack;
+        }
+
+        /**
+         * 设置是否响应返回键
+         */
+        @JavascriptInterface
+        public void setResponseBack(boolean responseBack) {
+            ActWeb.this.responseBack = responseBack;
         }
 
         @JavascriptInterface
@@ -377,7 +389,26 @@ public class ActWeb extends BaseCompatActivity {
                 }
             });
         }
+        @JavascriptInterface
+        public void finishAct() {
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    ActWeb.super.finish();
+                }
+            });
+        }
+
+    }
 
+    /**
+     * 是否响应返回键
+     */
+    private boolean responseBack = true;
+    @Override
+    public void onBackPressed() {
+        if(responseBack)
+            super.onBackPressed();
     }
 
     @Override

+ 110 - 101
app/src/main/java/com/sheep/gamegroup/view/activity/MiddleAct.java

@@ -54,114 +54,123 @@ public class MiddleAct extends Activity {
             for (String key : bundle.keySet()) {
                 if (BuildConfig.DEBUG)
                     System.out.println(String.format(Locale.CHINA, "key = %s,value = %s", key, bundle.get(key)));
-                if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
+                switch (key) {
+                    case JPushInterface.EXTRA_NOTIFICATION_ID:
 //                    sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));
-                } else if (key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)) {
+                        break;
+                    case JPushInterface.EXTRA_CONNECTION_CHANGE:
 //                    sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));
-                } else if (key.equals(JPushInterface.EXTRA_EXTRA)) {
-                    String data;
-                    if (TextUtils.isEmpty((data = bundle.getString(JPushInterface.EXTRA_EXTRA)))) {
-                        continue;
+                        break;
+                    case JPushInterface.EXTRA_EXTRA:
+                        String data;
+                        if (TextUtils.isEmpty((data = bundle.getString(JPushInterface.EXTRA_EXTRA)))) {
+                            continue;
+                        }
+                        JPushMessage msg = JSONObject.parseObject(data, JPushMessage.class);
+                        Activity activity = this;
+                        gotoNext(activity, bundle, msg);
+                        break;
+                    default:
+//                    sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
+                        break;
+                }
+            }
+        }
+    }
+
+    private void gotoNext(Activity activity, Bundle bundle, JPushMessage msg) {
+        switch (msg.getType()) {
+            case 11://试玩赚钱
+                Jump2View.getInstance().goTryplayView(activity, null);
+                break;
+            case 12://任务详情: 任务的id
+                Jump2View.getInstance().goTaskDetailView(activity, msg.getId());
+                break;
+            case 13://任务记录
+                Jump2View.getInstance().goTaskList2View(activity, null);
+                break;
+            case 21://邀请赚钱
+                Jump2View.getInstance().goAskGetMoney(activity, null);
+                break;
+            case 31://办卡赚钱
+                Jump2View.getInstance().goCreditCardTaskList(activity, null);
+                break;
+            case 32://跳转到信用卡详情界面: id 信用卡任务的id
+                Jump2View.getInstance().goCreditCardTaskDetail(activity, msg.getId());
+                break;
+            case 33://跳转到信用卡web申请界面; id 信用卡信息的id
+                Jump2View.getInstance().tryGoCreditCardWeb(activity, 0, msg.getId(), new Action1<String>() {
+                    @Override
+                    public void call(String msg) {
+                        if (msg != null) {
+                            G.showToast(msg);
+                        }
                     }
-                    JPushMessage msg = JSONObject.parseObject(data, JPushMessage.class);
-                    Activity activity = this;
-                    switch (msg.getType()) {
-                        case 11://试玩赚钱
-                            Jump2View.getInstance().goTryplayView(activity, null);
-                            break;
-                        case 12://任务详情: 任务的id
-                            Jump2View.getInstance().goTaskDetailView(activity, msg.getId());
-                            break;
-                        case 13://任务记录
-                            Jump2View.getInstance().goTaskList2View(activity, null);
-                            break;
-                        case 21://邀请赚钱
-                            Jump2View.getInstance().goAskGetMoney(activity, null);
-                            break;
-                        case 31://办卡赚钱
-                            Jump2View.getInstance().goCreditCardTaskList(activity, null);
-                            break;
-                        case 32://跳转到信用卡详情界面: id 信用卡任务的id
-                            Jump2View.getInstance().goCreditCardTaskDetail(activity, msg.getId());
-                            break;
-                        case 33://跳转到信用卡web申请界面; id 信用卡信息的id
-                            Jump2View.getInstance().tryGoCreditCardWeb(activity, 0, msg.getId(), new Action1<String>() {
-                                @Override
-                                public void call(String msg) {
-                                    if(msg != null){
-                                        G.showToast(msg);
-                                    }
-                                }
-                            });
-                            break;
-                        case 41://躺着赚钱
-                            Jump2View.getInstance().tryGoLyingView(activity, null);
-                            break;
-                        case 42://跳转到修改 挂机微信账号密码 到服务器 界面
-                            Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), ALTER_INFO);
-                            break;
-                        case 43://跳转到提交 挂机微信验证码 到服务器 界面
-                            Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), ALTER_CODE);
-                            break;
-                        case 44://跳转到提交 挂机微信账号已经解封 到服务器 界面
-                            Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), HAS_DEBLOCKED);
-                            break;
-                        case 51://微信辅助任务
-                            Jump2View.getInstance().tryGoWxfz(activity, null);
-                            break;
-                        case 61://个人中心
-                            Jump2View.getInstance().goPersonnalCenterView(activity, null);
-                            break;
-                        case 62://提现
-                            Jump2View.getInstance().tryGoWithdrawal(activity, null);
-                            break;
-                        case 621://提现结果页面
-                            Jump2View.getInstance().goWithdrawalResultview(activity, NumberFormatUtils.parseFloat(msg.getMsg()));
-                            break;
-                        case 63://充值Q币
-                            Jump2View.getInstance().goRechargeQAct(activity,"推送");
-                            break;
-                        case 64://充值绵羊币
-                            Jump2View.getInstance().goRechargeAct(activity,"推送");
-                            break;
-                        case 65://我的资产
-                            Jump2View.getInstance().goMyMoney(activity,null);
-                            break;
+                });
+                break;
+            case 41://躺着赚钱
+                Jump2View.getInstance().tryGoLyingView(activity, null);
+                break;
+            case 42://跳转到修改 挂机微信账号密码 到服务器 界面
+                Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), ALTER_INFO);
+                break;
+            case 43://跳转到提交 挂机微信验证码 到服务器 界面
+                Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), ALTER_CODE);
+                break;
+            case 44://跳转到提交 挂机微信账号已经解封 到服务器 界面
+                Jump2View.getInstance().goCommitWxCodeOnHookView(activity, msg.getId(), msg.getMsg(), HAS_DEBLOCKED);
+                break;
+            case 51://微信辅助任务
+                Jump2View.getInstance().tryGoWxfz(activity, null);
+                break;
+            case 61://个人中心
+                Jump2View.getInstance().goPersonnalCenterView(activity, null);
+                break;
+            case 62://提现
+                Jump2View.getInstance().tryGoWithdrawal(activity, null);
+                break;
+            case 621://提现结果页面
+                Jump2View.getInstance().goWithdrawalResultview(activity, NumberFormatUtils.parseFloat(msg.getMsg()));
+                break;
+            case 63://充值Q币
+                Jump2View.getInstance().goRechargeQAct(activity, "推送");
+                break;
+            case 64://充值绵羊币
+                Jump2View.getInstance().goRechargeAct(activity, "推送");
+                break;
+            case 65://我的资产
+                Jump2View.getInstance().goMyMoney(activity, null);
+                break;
 //                        case 66://安全中心
 //                            Jump2View.getInstance().goAccountAndSecurit(activity,null);
 //                            break;
-                        case 71://浏览器打开web界面: url h5链接
-                            Jump2View.getInstance().goWeb(activity, msg.getUrl());
-                            break;
-                        case 72://App web界面: url h5链接  title 标题
-                            Jump2View.getInstance().goWeb(activity, msg.getUrl(), TextUtils.isEmpty(msg.getTitle()) ? bundle.getString(JPushInterface.EXTRA_ALERT) : msg.getTitle());
-                            break;
+            case 71://浏览器打开web界面: url h5链接
+                Jump2View.getInstance().goWeb(activity, msg.getUrl());
+                break;
+            case 72://App web界面: url h5链接  title 标题
+                Jump2View.getInstance().goWeb(activity, msg.getUrl(), TextUtils.isEmpty(msg.getTitle()) ? bundle.getString(JPushInterface.EXTRA_ALERT) : msg.getTitle());
+                break;
 
-                        case 1://跳转到首页: id 0,小绵羊 1,游戏
-                            if(msg.getId() == 0)
-                                Jump2View.getInstance().goHomePageView(activity, msg.getId() % MainTab.values().length);
-                            else if(msg.getId() == 1)
-                                Jump2View.getInstance().goMainGame(activity);
-                            break;
-                        case 2://公告: title 标题   msg 内容
-                            Jump2View.getInstance().goNotice(activity, TextUtils.isEmpty(msg.getTitle()) ? bundle.getString(JPushInterface.EXTRA_ALERT) : msg.getTitle(), msg.getMsg(), msg.getTime() == 0 ? System.currentTimeMillis() : msg.getTime());
-                            break;
-                        case 3://下载: url 下载链接
-                            if(msg.getUrl().startsWith("http"))
-                                TestUtil.webDownload(activity, msg.getUrl());
-                            break;
-                        case 9://打卡赚钱
-                            Jump2View.getInstance().goSignCardAct(activity, null);
-                            break;
-                        case 0://直接启动或者重启app
-                        default:
-                            Jump2View.getInstance().newTaskTopStartAct(activity, SplashAct.class, bundle);
-                            break;
-                    }
-                } else {
-//                    sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
-                }
-            }
+            case 1://跳转到首页: id 0,小绵羊 1,游戏
+                if (msg.getId() == 0)
+                    Jump2View.getInstance().goHomePageView(activity, msg.getId() % MainTab.values().length);
+                else if (msg.getId() == 1)
+                    Jump2View.getInstance().goMainGame(activity);
+                break;
+            case 2://公告: title 标题   msg 内容
+                Jump2View.getInstance().goNotice(activity, TextUtils.isEmpty(msg.getTitle()) ? bundle.getString(JPushInterface.EXTRA_ALERT) : msg.getTitle(), msg.getMsg(), msg.getTime() == 0 ? System.currentTimeMillis() : msg.getTime());
+                break;
+            case 3://下载: url 下载链接
+                if (msg.getUrl().startsWith("http"))
+                    TestUtil.webDownload(activity, msg.getUrl());
+                break;
+            case 9://打卡赚钱
+                Jump2View.getInstance().goSignCardAct(activity, null);
+                break;
+            case 0://直接启动或者重启app
+            default:
+                Jump2View.getInstance().newTaskTopStartAct(activity, SplashAct.class, bundle);
+                break;
         }
     }
 }

+ 40 - 64
app/src/main/java/com/sheep/gamegroup/view/activity/TaskDetailAct.java

@@ -89,6 +89,7 @@ import rx.functions.Action1;
 import rx.schedulers.Schedulers;
 
 import static com.sheep.gamegroup.util.UMConfigUtils.Event.GAME_INSTEAD_OF_RECHARGE_GET;
+import static com.sheep.gamegroup.util.DataUtil.REQUEST_CAPTURE_PERMISSION;
 
 /**
  * 任务详情页面
@@ -588,7 +589,12 @@ public class TaskDetailAct extends AbsChooseImageActivity implements TaskDetailC
                             ApkUtils.installApk(SheepApp.mContext, PackageUtil.isExistsFile(taskEty.getPackage_names()));
                             break;
                         case DownloadTaskService.STATUS_INSTALLED:
-                            PackageUtil.startApp(SheepApp.mContext, taskEty.getPackage_names());
+                            DataUtil.getInstance().requestCapturePermission(activity, new Action1<Integer>() {
+                                @Override
+                                public void call(Integer integer) {
+                                    PackageUtil.startApp(SheepApp.mContext, taskEty.getPackage_names());
+                                }
+                            });
                             break;
                         case 10:
                             Ext ext;
@@ -806,33 +812,40 @@ public class TaskDetailAct extends AbsChooseImageActivity implements TaskDetailC
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == 0 && resultCode == RESULT_OK) {
-            if (taskReleaseEty.getAccepted_task_id() > 0) {
-                showProgress(true);
-                SheepApp.getInstance()
-                        .getNetComponent()
-                        .getApiService()
-                        .giveUpTask(taskReleaseEty.getAccepted_task_id())
-                        .subscribeOn(Schedulers.io())
-                        .observeOn(AndroidSchedulers.mainThread())
-                        .subscribe(new SheepSubscriber<BaseMessage>(SheepApp.mContext) {
-                            @Override
-                            public void onError(BaseMessage baseMessage) {
-                                hideProgress();
-                                G.showToast(baseMessage);
-                            }
+        switch (requestCode){
+            case 0:
+                if (resultCode == RESULT_OK) {
+                    if (taskReleaseEty.getAccepted_task_id() > 0) {
+                        showProgress(true);
+                        SheepApp.getInstance()
+                                .getNetComponent()
+                                .getApiService()
+                                .giveUpTask(taskReleaseEty.getAccepted_task_id())
+                                .subscribeOn(Schedulers.io())
+                                .observeOn(AndroidSchedulers.mainThread())
+                                .subscribe(new SheepSubscriber<BaseMessage>(SheepApp.mContext) {
+                                    @Override
+                                    public void onError(BaseMessage baseMessage) {
+                                        hideProgress();
+                                        G.showToast(baseMessage);
+                                    }
 
-                            @Override
-                            public void onNext(BaseMessage baseMessage) {
-                                CommonUtil.getInstance().setTAskEnty(null);
-                                acceptedTask();
-                            }
-                        });
-            }
-        }
-        //图片展示
-        if(requestCode == 101){
-            isFresh = true;
+                                    @Override
+                                    public void onNext(BaseMessage baseMessage) {
+                                        CommonUtil.getInstance().setTAskEnty(null);
+                                        acceptedTask();
+                                    }
+                                });
+                    }
+                }
+                break;
+            case 101:
+                //图片展示
+                isFresh = true;
+                break;
+            default:
+                DataUtil.getInstance().onActivityResult(requestCode, resultCode, data);
+                break;
         }
     }
 
@@ -1067,43 +1080,6 @@ public class TaskDetailAct extends AbsChooseImageActivity implements TaskDetailC
             detail_task_recyclerview.setAdapter(sonListviewAdp);
         }
 
-        //自动审核
-        //todo 暂时不要
-//        if(taskEty.getInspect_type() == 3){
-//            taskdetail_user_use_layout.setVisibility(View.VISIBLE);
-//
-//            start_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            start_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            down_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            down_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            install_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            install_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//            if (taskEty != null) {
-//                int thisRun = taskEty.getRunTask();
-//                if (thisRun == 1) {//接受了任务
-//                    start_task_btntv.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                    start_task_line.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                    if (PackageUtil.isAppInstalled(SheepApp.mContext, taskEty.getPackage_names())) {
-//                        down_task_btntv.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                        down_task_line.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                        install_task_btntv.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                        install_task_line.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                    } else if(!TextUtils.isEmpty(PackageUtil.isExistsFile(taskEty.getPackage_names()))){
-//
-//                        down_task_btntv.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                        down_task_line.setBackground(getResources().getDrawable(R.drawable.selector_button_full_main));
-//                        install_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                        install_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                    } else {
-//                        down_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                        down_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                        install_task_btntv.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                        install_task_line.setBackground(getResources().getDrawable(R.drawable.sp_rectangle_bg_gray_radius));
-//                    }
-//                }
-//            }
-//        }
-
         //截至时间
         if(gettaskAcceptedEty != null &&taskReleaseEty != null && taskReleaseEty.isIs_running() && gettaskAcceptedEty.getEnd_time() > 0){
             CommonUtil.getInstance().getHashMap(end_of_time_tv);

+ 2 - 0
app/src/main/java/com/sheep/jiuyan/samllsheep/SheepApp.java

@@ -159,6 +159,7 @@ public class SheepApp extends BaseApplication {
                     LogUtil.println("SheepApp onActivityStarted", mActivityCount);
                     UMConfigUtils.Event.SHEEP_STARTED.onEvent();
                     Jump2View.getInstance().startFloat(activity, false);
+                    Jump2View.getInstance().startShotScreenFloat(activity, false);
                 }
             }
         }
@@ -181,6 +182,7 @@ public class SheepApp extends BaseApplication {
                     LogUtil.println("SheepApp onActivityStopped", mActivityCount);
                     UMConfigUtils.Event.SHEEP_STOPPED.onEvent();
                     Jump2View.getInstance().startFloat(activity, true);
+                    Jump2View.getInstance().startShotScreenFloat(activity, true);
                 }
             }
         }

+ 1 - 1
app/src/main/java/com/sheep/jiuyan/samllsheep/service/FloatService.java

@@ -149,6 +149,7 @@ public class FloatService extends Service {
     };
     @Override
     public void onDestroy() {
+        super.onDestroy();
         if (floatView != null) {
             try {
                 wm.removeViewImmediate(floatView);
@@ -157,7 +158,6 @@ public class FloatService extends Service {
             }
         }
         stopTimer();
-        super.onDestroy();
     }
 
 //    public static final String OPERATION = "operation";

+ 417 - 0
app/src/main/java/com/sheep/jiuyan/samllsheep/service/FloatShotScreenService.java

@@ -0,0 +1,417 @@
+package com.sheep.jiuyan.samllsheep.service;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.Image;
+import android.media.ImageReader;
+import android.media.projection.MediaProjection;
+import android.media.projection.MediaProjectionManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import com.sheep.gamegroup.util.DataUtil;
+import com.sheep.gamegroup.util.GlobalScreenShot;
+import com.sheep.jiuyan.samllsheep.R;
+import com.sheep.jiuyan.samllsheep.utils.G;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+import rx.functions.Func1;
+import rx.schedulers.Schedulers;
+
+import static com.sheep.gamegroup.util.DataUtil.REQUEST_CAPTURE_PERMISSION;
+
+/**
+ * Created by realicing on 2018/5/8.
+ * realicing@sina.com
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class FloatShotScreenService extends Service {
+
+    //不与Activity进行绑定.
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        createFloatView();
+        createImageReader();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (floatView != null) {
+            try {
+                wm.removeViewImmediate(floatView);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        stopVirtual();
+
+        tearDownMediaProjection();
+    }
+
+    //    public static final String OPERATION = "operation";
+    public static final int OPERATION_SHOW = 100;
+    public static final int OPERATION_HIDE = 101;
+
+    private static final int HANDLE_CHECK_ACTIVITY = 200;
+
+    private boolean isAdded = false; // 是否已增加悬浮窗
+    private static WindowManager wm;
+    private static WindowManager.LayoutParams params;
+    private View floatView;
+
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent != null) {
+            int type = intent.getIntExtra("type", 0);
+            switch (type) {
+                case 1:
+                    mResultData = (Intent) DataUtil.getInstance().getData(REQUEST_CAPTURE_PERMISSION);
+                    break;
+                case 0:
+                default:
+                    if (intent.getBooleanExtra("isShow", true)) {
+                        mHandler.sendEmptyMessageDelayed(OPERATION_SHOW, 1000L);
+                    } else {
+                        removeMessages();
+                        mHandler.sendEmptyMessage(OPERATION_HIDE);
+                    }
+                    break;
+            }
+        }
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    private void removeMessages() {
+        mHandler.removeMessages(OPERATION_HIDE);
+        mHandler.removeMessages(OPERATION_SHOW);
+    }
+
+    private Handler mHandler = new TwHandler(this);
+
+    static class TwHandler extends Handler {
+        TwHandler(FloatShotScreenService service) {
+            this.service = service;
+        }
+
+        FloatShotScreenService service;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case OPERATION_SHOW:
+                    if (!service.isAdded) {
+                        try {
+//                            service.floatView.setAlpha(1.0f);
+//                            wm.updateViewLayout(service.floatView, params);
+                            wm.addView(service.floatView, params);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        service.isAdded = true;
+                    }
+                    break;
+                case OPERATION_HIDE:
+                case HANDLE_CHECK_ACTIVITY:
+                    if (service.isAdded) {
+                        try {
+//                            service.floatView.setAlpha(0.0f);
+//                            wm.updateViewLayout(service.floatView, params);
+                            wm.removeViewImmediate(service.floatView);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        service.isAdded = false;
+                    }
+                    break;
+            }
+        }
+    }
+
+
+    /**
+     * 创建悬浮窗
+     */
+    private void createFloatView() {
+        //获取浮动窗口视图所在布局.
+        ImageView imageView = new ImageView(getApplicationContext());
+        imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_crop));
+        floatView = imageView;
+
+        wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
+        params = new WindowManager.LayoutParams();
+
+        // 设置window type
+//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){//6.0
+//            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+//        }else {
+//            params.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+//        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            //  大于等于 24 即为 7.0 及以上执行内容
+            Log.e("qx", "7.0");
+            params.type = WindowManager.LayoutParams.TYPE_PHONE; // 7.1
+        } else {
+            //  低于 24 即为 7.0 以下执行内容
+            params.type = WindowManager.LayoutParams.TYPE_TOAST;   // 4.4
+            Log.e("qx", "4.4");
+
+        }
+        /*
+         * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE; 那么优先级会降低一些,
+         * 即拉下通知栏不可见
+         */
+
+        params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
+
+        // 设置Window flag
+        params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        // 设置悬浮窗的Touch监听
+        floatView.setOnTouchListener(new View.OnTouchListener() {
+            int lastX, lastY;
+            int paramX, paramY;
+            private boolean isMove = false;
+            private long downTime = 0;
+
+            public boolean onTouch(View v, MotionEvent event) {
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        isMove = false;
+                        downTime = System.currentTimeMillis();
+                        lastX = (int) event.getRawX();
+                        lastY = (int) event.getRawY();
+                        paramX = params.x;
+                        paramY = params.y;
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        int dx = (int) event.getRawX() - lastX;
+                        int dy = (int) event.getRawY() - lastY;
+                        params.x = paramX + dx;
+                        params.y = paramY + dy;
+                        // 更新悬浮窗位置
+                        wm.updateViewLayout(floatView, params);
+                        isMove = true;
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        if (!isMove && System.currentTimeMillis() - downTime < 1000L) {//没有移动过并且小于1秒就弹起来就点击
+                            performClick();
+                        }
+                        isMove = false;
+                        break;
+                }
+                return false;
+            }
+        });
+
+        // 设置悬浮窗的长得宽
+        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.gravity = Gravity.START | Gravity.TOP;
+        params.x = G.WIDTH;
+        params.y = 100;
+
+        try {
+            wm.addView(floatView, params);
+            isAdded = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void performClick() {
+        // 设置点击悬浮窗的响应
+        startScreenShot();
+    }
+
+    private void startScreenShot() {
+
+        floatView.setVisibility(View.GONE);
+
+        Handler handler1 = new Handler();
+        handler1.postDelayed(new Runnable() {
+            public void run() {
+                //start virtual
+                startVirtual();
+            }
+        }, 5);
+
+        handler1.postDelayed(new Runnable() {
+            public void run() {
+                //capture the screen
+                startCapture();
+
+            }
+        }, 30);
+
+    }
+
+    private void createImageReader() {
+
+        mImageReader = ImageReader.newInstance(G.WIDTH, G.HEIGHT, PixelFormat.RGBA_8888, 1);
+
+    }
+
+    public void startVirtual() {
+        if (mMediaProjection != null) {
+            virtualDisplay();
+        } else if (mResultData == null && (mResultData = (Intent) DataUtil.getInstance().getData(REQUEST_CAPTURE_PERMISSION)) == null) {
+            G.showToast("请重新点击开始试玩");
+        } else {
+            setUpMediaProjection();
+            virtualDisplay();
+        }
+    }
+
+    public void setUpMediaProjection() {
+        mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData);
+    }
+
+    private MediaProjectionManager getMediaProjectionManager() {
+
+        return (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
+    }
+
+    private void virtualDisplay() {
+        mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",
+                G.WIDTH, G.HEIGHT, G.DENSITY_DPI, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+                mImageReader.getSurface(), null, null);
+    }
+
+    private void startCapture() {
+        Image image = mImageReader.acquireLatestImage();
+        if (image == null) {
+            startScreenShot();
+        } else {
+            Observable.just(image)
+                    .map(new Func1<Image, Bitmap>() {
+                        @Override
+                        public Bitmap call(Image image) {
+                            return getBitmapFromImage(image);
+                        }
+                    })
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(new Action1<Bitmap>() {
+                        @Override
+                        public void call(Bitmap bitmap) {
+                            //预览图片
+                            if (bitmap != null) {
+                                DataUtil.getInstance().putData(Bitmap.class.getSimpleName(), bitmap);
+                                new GlobalScreenShot(getApplicationContext()).takeScreenshot(bitmap, new GlobalScreenShot.onScreenShotListener() {
+                                    @Override
+                                    public void onStartShot() {
+
+                                    }
+
+                                    @Override
+                                    public void onFinishShot(boolean success) {
+                                        G.showToast("截图成功");
+                                    }
+                                }, true, true);
+                            }
+                            floatView.setVisibility(View.VISIBLE);
+                        }
+                    });
+        }
+    }
+
+    private Bitmap getBitmapFromImage(Image image) {
+        int width = image.getWidth();
+        int height = image.getHeight();
+        final Image.Plane[] planes = image.getPlanes();
+        final ByteBuffer buffer = planes[0].getBuffer();
+        //每个像素的间距
+        int pixelStride = planes[0].getPixelStride();
+        //总的间距
+        int rowStride = planes[0].getRowStride();
+        int rowPadding = rowStride - pixelStride * width;
+        Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
+        bitmap.copyPixelsFromBuffer(buffer);
+        bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
+        image.close();
+        File fileImage = null;
+        if (bitmap != null) {
+            try {
+                fileImage = DataUtil.getInstance().getScreenShotsFile();
+                if (!fileImage.exists()) {
+                    fileImage.createNewFile();
+                }
+                FileOutputStream out = new FileOutputStream(fileImage);
+                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+                out.flush();
+                out.close();
+                Intent media = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+                Uri contentUri = Uri.fromFile(fileImage);
+                media.setData(contentUri);
+                sendBroadcast(media);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+                fileImage = null;
+            } catch (IOException e) {
+                e.printStackTrace();
+                fileImage = null;
+            }
+        }
+
+        if (fileImage != null) {
+            return bitmap;
+        }
+        return null;
+    }
+
+    private MediaProjection mMediaProjection;
+    private VirtualDisplay mVirtualDisplay;
+
+    private Intent mResultData = null;
+
+
+    private ImageReader mImageReader;
+
+    private void tearDownMediaProjection() {
+        if (mMediaProjection != null) {
+            mMediaProjection.stop();
+            mMediaProjection = null;
+        }
+    }
+
+    private void stopVirtual() {
+        if (mVirtualDisplay == null) {
+            return;
+        }
+        mVirtualDisplay.release();
+        mVirtualDisplay = null;
+    }
+}

+ 1 - 0
app/src/main/java/com/sheep/jiuyan/samllsheep/utils/G.java

@@ -22,6 +22,7 @@ public class G {
     public static int HEIGHT = 1280;//屏幕高
     public static int WIDTH = 720;//屏幕宽
     public static float DENSITY = 2;//屏幕的Density
+    public static int DENSITY_DPI = 2;//屏幕的Density
 
     /**
      * @param str

BIN
app/src/main/res/drawable/screenshot_panel.9.png


+ 41 - 0
app/src/main/res/layout/global_screenshot.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/global_screenshot_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@android:color/black"
+        android:visibility="gone" />
+
+    <ImageView
+        android:id="@+id/global_screenshot"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:adjustViewBounds="true"
+        android:background="@drawable/screenshot_panel"
+        android:visibility="gone" />
+
+    <ImageView
+        android:id="@+id/global_screenshot_flash"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@android:color/white"
+        android:visibility="gone" />
+</FrameLayout>

BIN
app/src/main/res/mipmap-xxhdpi/ic_crop.webp