OSDN Git Service

DO NOT MERGE Fix android:noHistory for Wear
authorNed Burns <pixel@google.com>
Tue, 6 Dec 2016 20:52:01 +0000 (15:52 -0500)
committerNed Burns <pixel@google.com>
Wed, 7 Dec 2016 20:05:25 +0000 (15:05 -0500)
Modifies swipe-to-close activities to be opaque by default (instead
of translucent by default). Previously, android:noHistory properties
on most activities in Wear were being ignored because they were
usually transitioning to a swipe-to-close activity that was marked
as translucent. This meant that the noHistory activity was still
technically visible, and so would never be culled from the task
history.

Now, we convert a swiped activity to translucent as soon as a swipe
begins, and convert it back after the swipe finishes. The previous
version of SDL tries to do this, but fails in the case where the
context is a ContextWrapper.

This approach is hacky and isn't merge-able into master. We leave
it DO NOT MERGE and will do a long-term fix after the holidays.

Test: Built a test app to verify that noHistory is now being
correctly respected. Manually verified that new activities start
out opaque and not translucent. Manually verified that Home
correctly starts/stops when it's revealed from underneath a
partially swiped activity. Tested general swipe behavior on Settings,
Contacts, Flashlight, Fit.

Bug: 33252029

Change-Id: Ib2e7f21ea1e0d52db03e78d25676501e5f73b31f

core/java/com/android/internal/widget/SwipeDismissLayout.java
services/core/java/com/android/server/am/ActivityRecord.java

index 83b49eb..bdcfff2 100644 (file)
@@ -23,6 +23,7 @@ import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.TypedArray;
@@ -33,7 +34,6 @@ import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 
@@ -44,7 +44,6 @@ public class SwipeDismissLayout extends FrameLayout {
     private static final String TAG = "SwipeDismissLayout";
 
     private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
-    private boolean mUseDynamicTranslucency = true;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -64,6 +63,8 @@ public class SwipeDismissLayout extends FrameLayout {
         void onSwipeCancelled(SwipeDismissLayout layout);
     }
 
+    private boolean mIsWindowNativelyTranslucent;
+
     // Cached ViewConfiguration and system-wide constant values
     private int mSlop;
     private int mMinFlingVelocity;
@@ -83,19 +84,6 @@ public class SwipeDismissLayout extends FrameLayout {
 
     private OnDismissedListener mDismissedListener;
     private OnSwipeProgressChangedListener mProgressListener;
-    private ViewTreeObserver.OnEnterAnimationCompleteListener mOnEnterAnimationCompleteListener =
-            new ViewTreeObserver.OnEnterAnimationCompleteListener() {
-                @Override
-                public void onEnterAnimationComplete() {
-                    // SwipeDismissLayout assumes that the host Activity is translucent
-                    // and temporarily disables translucency when it is fully visible.
-                    // As soon as the user starts swiping, we will re-enable
-                    // translucency.
-                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
-                        ((Activity) getContext()).convertFromTranslucent();
-                    }
-                }
-            };
     private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
         private Runnable mRunnable = new Runnable() {
             @Override
@@ -141,8 +129,8 @@ public class SwipeDismissLayout extends FrameLayout {
         mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 com.android.internal.R.styleable.Theme);
-        mUseDynamicTranslucency = !a.hasValue(
-                com.android.internal.R.styleable.Window_windowIsTranslucent);
+        mIsWindowNativelyTranslucent = a.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, false);
         a.recycle();
     }
 
@@ -157,20 +145,12 @@ public class SwipeDismissLayout extends FrameLayout {
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        if (getContext() instanceof Activity) {
-            getViewTreeObserver().addOnEnterAnimationCompleteListener(
-                    mOnEnterAnimationCompleteListener);
-        }
         getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         getContext().unregisterReceiver(mScreenOffReceiver);
-        if (getContext() instanceof Activity) {
-            getViewTreeObserver().removeOnEnterAnimationCompleteListener(
-                    mOnEnterAnimationCompleteListener);
-        }
         super.onDetachedFromWindow();
     }
 
@@ -273,9 +253,6 @@ public class SwipeDismissLayout extends FrameLayout {
                 mLastX = ev.getRawX();
                 updateSwiping(ev);
                 if (mSwiping) {
-                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
-                        ((Activity) getContext()).convertToTranslucent(null, null);
-                    }
                     setProgress(ev.getRawX() - mDownX);
                     break;
                 }
@@ -298,8 +275,11 @@ public class SwipeDismissLayout extends FrameLayout {
     }
 
     protected void cancel() {
-        if (mUseDynamicTranslucency && getContext() instanceof Activity) {
-            ((Activity) getContext()).convertFromTranslucent();
+        if (!mIsWindowNativelyTranslucent) {
+            Activity activity = findActivity();
+            if (activity != null) {
+                activity.convertFromTranslucent();
+            }
         }
         if (mProgressListener != null) {
             mProgressListener.onSwipeCancelled(this);
@@ -323,6 +303,7 @@ public class SwipeDismissLayout extends FrameLayout {
     }
 
     private void updateSwiping(MotionEvent ev) {
+        boolean oldSwiping = mSwiping;
         if (!mSwiping) {
             float deltaX = ev.getRawX() - mDownX;
             float deltaY = ev.getRawY() - mDownY;
@@ -332,6 +313,16 @@ public class SwipeDismissLayout extends FrameLayout {
                 mSwiping = false;
             }
         }
+
+        if (mSwiping && !oldSwiping) {
+            // Swiping has started
+            if (!mIsWindowNativelyTranslucent) {
+                Activity activity = findActivity();
+                if (activity != null) {
+                    activity.convertToTranslucent(null, null);
+                }
+            }
+        }
     }
 
     private void updateDismiss(MotionEvent ev) {
@@ -406,6 +397,17 @@ public class SwipeDismissLayout extends FrameLayout {
         return 1 - progress * progress * progress;
     }
 
+    private Activity findActivity() {
+        Context context = getContext();
+        while (context instanceof ContextWrapper) {
+            if (context instanceof Activity) {
+                return (Activity) context;
+            }
+            context = ((ContextWrapper) context).getBaseContext();
+        }
+        return null;
+    }
+
     private class DismissAnimator implements AnimatorUpdateListener, Animator.AnimatorListener {
         private final TimeInterpolator DISMISS_INTERPOLATOR = new DecelerateInterpolator(1.5f);
         private final long DISMISS_DURATION = 250;
index 3f69712..7ada47a 100755 (executable)
@@ -710,12 +710,7 @@ final class ActivityRecord {
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window, userId);
             final boolean translucent = ent != null && (ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
-                    || (!ent.array.hasValue(
-                            com.android.internal.R.styleable.Window_windowIsTranslucent)
-                            && ent.array.getBoolean(
-                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
-                                            false)));
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false));
             fullscreen = ent != null && !ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowIsFloating, false)
                     && !translucent;