diff options
| author | 2017-01-03 21:58:48 +0000 | |
|---|---|---|
| committer | 2017-01-03 21:58:52 +0000 | |
| commit | da8b27ce0943b5d273781c96bcd3b146f46e63c7 (patch) | |
| tree | 6b7781c8ea43725539aa7fa93fa560f554a7d7b8 | |
| parent | 9bab1c4dd505903dbdd7403ea38d8b9d449e9be4 (diff) | |
| parent | c75ffe8ccb58966753654c5b817507ad11168bca (diff) | |
Merge "Fixing some interaction issues with the PIP menu."
6 files changed, 206 insertions, 88 deletions
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 5c2787b0f04a..5574753bee6c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -427,6 +427,7 @@ android:supportsPictureInPicture="true" android:stateNotNeeded="true" android:taskAffinity="" + android:launchMode="singleTop" androidprv:alwaysFocusable="true" /> <!-- platform logo easter egg activity --> diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml index 054bfabb2f84..cadc09b23c4e 100644 --- a/packages/SystemUI/res/layout/pip_menu_activity.xml +++ b/packages/SystemUI/res/layout/pip_menu_activity.xml @@ -19,7 +19,7 @@ android:id="@+id/menu" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#33000000"> + android:background="#66000000"> <LinearLayout android:id="@+id/actions" @@ -45,7 +45,7 @@ android:text="@string/pip_phone_dismiss" android:background="?android:selectableItemBackground" /> <TextView - android:id="@+id/minimize" + android:id="@+id/expand" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" @@ -53,7 +53,7 @@ android:textSize="12sp" android:textColor="#ffffffff" android:fontFamily="sans-serif" - android:text="@string/pip_phone_minimize" + android:text="@string/pip_phone_expand" android:background="?android:selectableItemBackground" /> </LinearLayout> </FrameLayout> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index fc1d816993b7..614472a7fd01 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -68,7 +68,7 @@ <item name="android:windowIsTranslucent">true</item> <item name="android:windowNoTitle">true</item> <item name="android:windowContentOverlay">@null</item> - <item name="android:windowBackground">@drawable/forced_resizable_background</item> + <item name="android:windowBackground">@null</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:statusBarColor">@color/transparent</item> <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item> diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index fe8ee6f6b27f..e4f78161faed 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -16,13 +16,16 @@ package com.android.systemui.pip.phone; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; -import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; import android.content.Intent; import android.content.pm.ParceledListSlice; +import android.graphics.PointF; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -30,11 +33,15 @@ import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.WindowManager.LayoutParams; import android.widget.ImageView; import android.widget.TextView; +import com.android.systemui.Interpolators; import com.android.systemui.R; import java.util.ArrayList; @@ -47,28 +54,40 @@ public class PipMenuActivity extends Activity { private static final String TAG = "PipMenuActivity"; - public static final int MESSAGE_FINISH_SELF = 1; - public static final int MESSAGE_UPDATE_ACTIONS = 2; + public static final int MESSAGE_SHOW_MENU = 1; + public static final int MESSAGE_HIDE_MENU = 2; + public static final int MESSAGE_UPDATE_ACTIONS = 3; private static final long INITIAL_DISMISS_DELAY = 2000; private static final long POST_INTERACTION_DISMISS_DELAY = 1500; + private static final long MENU_FADE_DURATION = 125; - private List<RemoteAction> mActions = new ArrayList<>(); + private boolean mMenuVisible; + private final List<RemoteAction> mActions = new ArrayList<>(); + private View mMenuContainer; private View mDismissButton; - private View mMinimizeButton; + private View mExpandButton; + private ObjectAnimator mMenuContainerAnimator; + + private PointF mDownPosition = new PointF(); + private PointF mDownDelta = new PointF(); + private ViewConfiguration mViewConfig; private Handler mHandler = new Handler(); private Messenger mToControllerMessenger; private Messenger mMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { + case MESSAGE_SHOW_MENU: + showMenu(); + break; + case MESSAGE_HIDE_MENU: + hideMenu(); + break; case MESSAGE_UPDATE_ACTIONS: setActions(((ParceledListSlice) msg.obj).getList()); break; - case MESSAGE_FINISH_SELF: - finish(); - break; } } }); @@ -76,12 +95,17 @@ public class PipMenuActivity extends Activity { private final Runnable mFinishRunnable = new Runnable() { @Override public void run() { - finish(); + hideMenu(); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { + // Set the flags to allow us to watch for outside touches and also hide the menu and start + // manipulating the PIP in the same touch gesture + mViewConfig = ViewConfiguration.get(this); + getWindow().addFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | LayoutParams.FLAG_SLIPPERY); + super.onCreate(savedInstanceState); setContentView(R.layout.pip_menu_activity); @@ -94,44 +118,74 @@ public class PipMenuActivity extends Activity { setActions(actions.getList()); } - findViewById(R.id.menu).setOnClickListener((v) -> { + mMenuContainer = findViewById(R.id.menu); + mMenuContainer.setOnClickListener((v) -> { expandPip(); }); mDismissButton = findViewById(R.id.dismiss); mDismissButton.setOnClickListener((v) -> { dismissPip(); }); - mMinimizeButton = findViewById(R.id.minimize); - mMinimizeButton.setOnClickListener((v) -> { - minimizePip(); + mExpandButton = findViewById(R.id.expand); + mExpandButton.setOnClickListener((v) -> { + expandPip(); }); + + notifyActivityCallback(mMessenger); + showMenu(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + showMenu(); } @Override protected void onStart() { super.onStart(); - notifyActivityVisibility(true); + notifyMenuVisibility(true); repostDelayedFinish(INITIAL_DISMISS_DELAY); } @Override + public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { + if (!isInPictureInPictureMode) { + finish(); + } + } + + @Override public void onUserInteraction() { repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY); } @Override - protected void onStop() { - super.onStop(); - finish(); + public boolean dispatchTouchEvent(MotionEvent ev) { + // On the first action outside the window, hide the menu + switch (ev.getAction()) { + case MotionEvent.ACTION_OUTSIDE: + hideMenu(); + break; + case MotionEvent.ACTION_DOWN: + mDownPosition.set(ev.getX(), ev.getY()); + break; + case MotionEvent.ACTION_MOVE: + mDownDelta.set(ev.getX() - mDownPosition.x, ev.getY() - mDownPosition.y); + if (mDownDelta.length() > mViewConfig.getScaledTouchSlop() && mMenuVisible) { + hideMenu(); + mMenuVisible = false; + } + } + return super.dispatchTouchEvent(ev); } @Override public void finish() { - View v = getWindow().getDecorView(); - v.removeCallbacks(mFinishRunnable); - notifyActivityVisibility(false); + notifyActivityCallback(null); super.finish(); - overridePendingTransition(0, R.anim.forced_resizable_exit); + // Hide without an animation (the menu should already be invisible at this point) + overridePendingTransition(0, 0); } @Override @@ -139,6 +193,51 @@ public class PipMenuActivity extends Activity { // Do nothing } + private void showMenu() { + if (!mMenuVisible) { + if (mMenuContainerAnimator != null) { + mMenuContainerAnimator.cancel(); + } + + notifyMenuVisibility(true); + mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA, + mMenuContainer.getAlpha(), 1f); + mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN); + mMenuContainerAnimator.setDuration(MENU_FADE_DURATION); + mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + repostDelayedFinish(INITIAL_DISMISS_DELAY); + } + }); + mMenuContainerAnimator.start(); + } + } + + private void hideMenu() { + hideMenu(null /* animationFinishedRunnable */); + } + + private void hideMenu(final Runnable animationFinishedRunnable) { + if (mMenuVisible) { + cancelDelayedFinish(); + notifyMenuVisibility(false); + mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA, + mMenuContainer.getAlpha(), 0f); + mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT); + mMenuContainerAnimator.setDuration(MENU_FADE_DURATION); + mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animationFinishedRunnable != null) { + animationFinishedRunnable.run(); + } + } + }); + mMenuContainerAnimator.start(); + } + } + private void setActions(List<RemoteAction> actions) { mActions.clear(); mActions.addAll(actions); @@ -173,17 +272,19 @@ public class PipMenuActivity extends Activity { } } - private void notifyActivityVisibility(boolean visible) { + private void notifyMenuVisibility(boolean visible) { + mMenuVisible = visible; Message m = Message.obtain(); - m.what = PipMenuActivityController.MESSAGE_ACTIVITY_VISIBILITY_CHANGED; + m.what = PipMenuActivityController.MESSAGE_MENU_VISIBILITY_CHANGED; m.arg1 = visible ? 1 : 0; - m.replyTo = visible ? mMessenger : null; sendMessage(m, "Could not notify controller of PIP menu visibility"); } private void expandPip() { - sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP, - "Could not notify controller to expand PIP"); + hideMenu(() -> { + sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP, + "Could not notify controller to expand PIP"); + }); } private void minimizePip() { @@ -192,8 +293,17 @@ public class PipMenuActivity extends Activity { } private void dismissPip() { - sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP, - "Could not notify controller to dismiss PIP"); + hideMenu(() -> { + sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP, + "Could not notify controller to dismiss PIP"); + }); + } + + private void notifyActivityCallback(Messenger callback) { + Message m = Message.obtain(); + m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK; + m.replyTo = callback; + sendMessage(m, "Could not notify controller of activity finished"); } private void sendEmptyMessage(int what, String errorMsg) { @@ -210,6 +320,11 @@ public class PipMenuActivity extends Activity { } } + private void cancelDelayedFinish() { + View v = getWindow().getDecorView(); + v.removeCallbacks(mFinishRunnable); + } + private void repostDelayedFinish(long delay) { View v = getWindow().getDecorView(); v.removeCallbacks(mFinishRunnable); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 64e2d1a7ff07..0350cc60a97a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -25,10 +25,11 @@ public class PipMenuActivityController { public static final String EXTRA_CONTROLLER_MESSENGER = "messenger"; public static final String EXTRA_ACTIONS = "actions"; - public static final int MESSAGE_ACTIVITY_VISIBILITY_CHANGED = 100; + public static final int MESSAGE_MENU_VISIBILITY_CHANGED = 100; public static final int MESSAGE_EXPAND_PIP = 101; public static final int MESSAGE_MINIMIZE_PIP = 102; public static final int MESSAGE_DISMISS_PIP = 103; + public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104; /** * A listener interface to receive notification on changes in PIP. @@ -67,34 +68,25 @@ public class PipMenuActivityController { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MESSAGE_ACTIVITY_VISIBILITY_CHANGED: { + case MESSAGE_MENU_VISIBILITY_CHANGED: { boolean visible = msg.arg1 > 0; - int listenerCount = mListeners.size(); - for (int i = 0; i < listenerCount; i++) { - mListeners.get(i).onPipMenuVisibilityChanged(visible); - } - mToActivityMessenger = msg.replyTo; + mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible)); break; } case MESSAGE_EXPAND_PIP: { - int listenerCount = mListeners.size(); - for (int i = 0; i < listenerCount; i++) { - mListeners.get(i).onPipExpand(); - } + mListeners.forEach(l -> l.onPipExpand()); break; } case MESSAGE_MINIMIZE_PIP: { - int listenerCount = mListeners.size(); - for (int i = 0; i < listenerCount; i++) { - mListeners.get(i).onPipMinimize(); - } + mListeners.forEach(l -> l.onPipMinimize()); break; } case MESSAGE_DISMISS_PIP: { - int listenerCount = mListeners.size(); - for (int i = 0; i < listenerCount; i++) { - mListeners.get(i).onPipDismiss(); - } + mListeners.forEach(l -> l.onPipDismiss()); + break; + } + case MESSAGE_UPDATE_ACTIVITY_CALLBACK: { + mToActivityMessenger = msg.replyTo; break; } } @@ -121,24 +113,34 @@ public class PipMenuActivityController { * Shows the menu activity. */ public void showMenu() { - // Start the menu activity on the top task of the pinned stack - try { - StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); - if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null && - pinnedStackInfo.taskIds.length > 0) { - Intent intent = new Intent(mContext, PipMenuActivity.class); - intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger); - intent.putExtra(EXTRA_ACTIONS, mActions); - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchTaskId( - pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]); - options.setTaskOverlay(true); - mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); - } else { - Log.e(TAG, "No PIP tasks found"); + if (mToActivityMessenger != null) { + Message m = Message.obtain(); + m.what = PipMenuActivity.MESSAGE_SHOW_MENU; + try { + mToActivityMessenger.send(m); + } catch (RemoteException e) { + Log.e(TAG, "Could not notify menu to show", e); + } + } else { + // Start the menu activity on the top task of the pinned stack + try { + StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); + if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null && + pinnedStackInfo.taskIds.length > 0) { + Intent intent = new Intent(mContext, PipMenuActivity.class); + intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger); + intent.putExtra(EXTRA_ACTIONS, mActions); + ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0); + options.setLaunchTaskId( + pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]); + options.setTaskOverlay(true); + mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); + } else { + Log.e(TAG, "No PIP tasks found"); + } + } catch (RemoteException e) { + Log.e(TAG, "Error showing PIP menu activity", e); } - } catch (RemoteException e) { - Log.e(TAG, "Error showing PIP menu activity", e); } } @@ -148,13 +150,12 @@ public class PipMenuActivityController { public void hideMenu() { if (mToActivityMessenger != null) { Message m = Message.obtain(); - m.what = PipMenuActivity.MESSAGE_FINISH_SELF; + m.what = PipMenuActivity.MESSAGE_HIDE_MENU; try { mToActivityMessenger.send(m); } catch (RemoteException e) { - Log.e(TAG, "Could not notify menu activity to finish", e); + Log.e(TAG, "Could not notify menu to hide", e); } - mToActivityMessenger = null; } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index ff3cc7981bd9..380e4683a7f4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -174,7 +174,7 @@ public class PipTouchHandler implements TunerService.Tunable { @Override public void onPipDismiss() { - animateDismissPinnedStack(mPinnedStackBounds); + BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack); } } @@ -328,26 +328,31 @@ public class PipTouchHandler implements TunerService.Tunable { * Registers the input consumer. */ private void registerInputConsumer() { - final InputChannel inputChannel = new InputChannel(); - try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); - mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel); - } catch (RemoteException e) { - Log.e(TAG, "Failed to create PIP input consumer", e); + if (mInputEventReceiver == null) { + final InputChannel inputChannel = new InputChannel(); + try { + mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); + mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel); + } catch (RemoteException e) { + Log.e(TAG, "Failed to create PIP input consumer", e); + } + mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper()); } - mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper()); } /** * Unregisters the input consumer. */ private void unregisterInputConsumer() { - try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); - } catch (RemoteException e) { - Log.e(TAG, "Failed to destroy PIP input consumer", e); + if (mInputEventReceiver != null) { + try { + mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); + } catch (RemoteException e) { + Log.e(TAG, "Failed to destroy PIP input consumer", e); + } + mInputEventReceiver.dispose(); + mInputEventReceiver = null; } - mInputEventReceiver.dispose(); } /** @@ -761,10 +766,6 @@ public class PipTouchHandler implements TunerService.Tunable { private PipTouchGesture mTapThroughGesture = new PipTouchGesture() { @Override boolean onMove(PipTouchState touchState) { - if (mEnableTapThrough && touchState.startedDragging()) { - mIsTappingThrough = false; - mMenuController.hideMenu(); - } return false; } |