summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml6
-rw-r--r--packages/SystemUI/res/values/styles.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java171
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java35
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;
}