summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2016-11-03 17:48:09 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-11-03 17:48:12 +0000
commit34f47747f7b0916f42ba9ffb25f1b4f21dce6d35 (patch)
tree5f9889817b51cc193f14da539d5b093f0d3393f0
parent609f164295e6734118ef9aca2669d157167cfb8d (diff)
parentdff5c08bfd5c15f11b71ce953282ed519ff1b290 (diff)
Merge changes I0d6f2f0c,I278ab8c3
* changes: Experiment for snapping PIP to closest edge. Experiment with allowing tap to break through to interact with the PIP.
-rw-r--r--core/java/android/view/IPinnedStackController.aidl5
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java10
-rw-r--r--packages/SystemUI/AndroidManifest.xml12
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml36
-rw-r--r--packages/SystemUI/res/values/strings.xml19
-rw-r--r--packages/SystemUI/res/values/styles.xml18
-rw-r--r--packages/SystemUI/res/xml/tuner_prefs.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java126
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java113
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java7
12 files changed, 483 insertions, 17 deletions
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index 830591d5b503..a81eef831f4e 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -30,4 +30,9 @@ interface IPinnedStackController {
* Notifies the controller that the user is currently interacting with the PIP.
*/
oneway void setInInteractiveMode(boolean inInteractiveMode);
+
+ /**
+ * Notifies the controller that the desired snap mode is to the closest edge.
+ */
+ oneway void setSnapToEdge(boolean snapToEdge);
}
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 45b7b0183fd8..cbacf269a0f0 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -46,7 +46,8 @@ public class PipSnapAlgorithm {
private final Context mContext;
private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
- private final int mSnapMode = SNAP_MODE_CORNERS_ONLY;
+ private final int mDefaultSnapMode = SNAP_MODE_CORNERS_ONLY;
+ private int mSnapMode = mDefaultSnapMode;
private Scroller mScroller;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -65,6 +66,13 @@ public class PipSnapAlgorithm {
}
/**
+ * Enables snapping to the closest edge.
+ */
+ public void setSnapToEdge(boolean snapToEdge) {
+ mSnapMode = snapToEdge ? SNAP_MODE_EDGE : mDefaultSnapMode;
+ }
+
+ /**
* @return the closest absolute snap stack bounds for the given {@param stackBounds} moving at
* the given {@param velocityX} and {@param velocityY}. The {@param movementBounds} should be
* those for the given {@param stackBounds}.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4d59d574adc8..2adb26159622 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -415,6 +415,18 @@
android:launchMode="singleTop"
android:excludeFromRecents="true" />
+ <activity
+ android:name=".pip.phone.PipMenuActivity"
+ android:theme="@style/PipPhoneOverlayControlTheme"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:resizeableActivity="true"
+ android:supportsPictureInPicture="true"
+ android:stateNotNeeded="true"
+ android:taskAffinity=""
+ androidprv:alwaysFocusable="true" />
+
<!-- platform logo easter egg activity -->
<activity
android:name=".DessertCase"
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
new file mode 100644
index 000000000000..88e6e725c976
--- /dev/null
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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"
+ android:background="#33000000">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
+ <Button
+ android:id="@+id/expand_pip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textSize="14sp"
+ android:textColor="#ffffffff"
+ android:text="@string/pip_phone_expand"
+ android:fontFamily="sans-serif" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d8c8b82eee4a..37a7e38eb4f9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1675,6 +1675,9 @@
not appear on production builds ever. -->
<string name="tuner_doze_always_on" translatable="false">Always on</string>
+ <!-- Making the PIP fullscreen -->
+ <string name="pip_phone_expand">Expand</string>
+
<!-- PIP section of the tuner. Non-translatable since it should
not appear on production builds ever. -->
<string name="picture_in_picture" translatable="false">Picture-in-Picture</string>
@@ -1695,4 +1698,20 @@
not appear on production builds ever. -->
<string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
+ <!-- PIP tap once to break through to the activity. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_tap_through_title" translatable="false">Tap to interact</string>
+
+ <!-- PIP tap once to break through to the activity. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_tap_through_summary" translatable="false">Tap once to interact with the activity</string>
+
+ <!-- PIP snap to closest edge. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_snap_mode_edge_title" translatable="false">Snap to closest edge</string>
+
+ <!-- PIP snap to closest edge. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_snap_mode_edge_summary" translatable="false">Snap to the closest edge</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e5bc8b996cea..6661f076d848 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -56,6 +56,24 @@
<item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
</style>
+ <style name="PipPhoneOverlayControlTheme" parent="@android:style/Theme.Material">
+ <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:colorBackgroundCacheHint">@null</item>
+ <item name="android:statusBarColor">@color/transparent</item>
+ <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item>
+ </style>
+
+ <style name="Animation.PipPhoneOverlayControl" parent="@android:style/Animation">
+ <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
+
+ <!-- If the target stack doesn't have focus, we do a task to front animation. -->
+ <item name="android:taskToFrontEnterAnimation">@anim/forced_resizable_enter</item>
+ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
+ </style>
+
<style name="TextAppearance.StatusBar.HeadsUp"
parent="@*android:style/TextAppearance.StatusBar">
</style>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 942f8472b7ef..f09d6e9fe052 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -137,6 +137,18 @@
android:summary="@string/pip_drag_to_dismiss_summary"
sysui:defValue="true" />
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="pip_tap_through"
+ android:title="@string/pip_tap_through_title"
+ android:summary="@string/pip_tap_through_summary"
+ sysui:defValue="false" />
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="pip_snap_mode_edge"
+ android:title="@string/pip_snap_mode_edge_title"
+ android:summary="@string/pip_snap_mode_edge_summary"
+ sysui:defValue="false" />
+
</PreferenceScreen>
<PreferenceScreen
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index f9a4f7ced6cc..7b8d27eef8b4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -34,6 +34,7 @@ public class PipManager {
private IActivityManager mActivityManager;
private IWindowManager mWindowManager;
+ private PipMenuActivityController mMenuController;
private PipTouchHandler mTouchHandler;
private PipManager() {}
@@ -46,7 +47,9 @@ public class PipManager {
mActivityManager = ActivityManagerNative.getDefault();
mWindowManager = WindowManagerGlobal.getWindowManagerService();
- mTouchHandler = new PipTouchHandler(context, mActivityManager, mWindowManager);
+ mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager);
+ mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager,
+ mWindowManager);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
new file mode 100644
index 000000000000..bfe5cff90a24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.pip.phone;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.View;
+import com.android.systemui.R;
+
+/**
+ * Translucent activity that gets started on top of a task in PIP to allow the user to control it.
+ */
+public class PipMenuActivity extends Activity {
+
+ private static final String TAG = "PipMenuActivity";
+
+ public static final int MESSAGE_FINISH_SELF = 2;
+
+ private static final long INITIAL_DISMISS_DELAY = 2000;
+ private static final long POST_INTERACTION_DISMISS_DELAY = 1500;
+
+ private Messenger mToControllerMessenger;
+ private Messenger mMessenger = new Messenger(new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_FINISH_SELF:
+ finish();
+ break;
+ }
+ }
+ });
+
+ private final Runnable mFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ }
+ };
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent startingIntet = getIntent();
+ mToControllerMessenger = startingIntet.getParcelableExtra(
+ PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER);
+
+ setContentView(R.layout.pip_menu_activity);
+ findViewById(R.id.expand_pip).setOnClickListener((view) -> {
+ finish();
+ notifyExpandPip();
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ notifyActivityVisibility(true);
+ repostDelayedFinish(INITIAL_DISMISS_DELAY);
+ }
+
+ @Override
+ public void onUserInteraction() {
+ repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ finish();
+ }
+
+ @Override
+ public void finish() {
+ View v = getWindow().getDecorView();
+ v.removeCallbacks(mFinishRunnable);
+ notifyActivityVisibility(false);
+ super.finish();
+ overridePendingTransition(0, R.anim.forced_resizable_exit);
+ }
+
+ @Override
+ public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
+ // Do nothing
+ }
+
+ private void notifyActivityVisibility(boolean visible) {
+ Message m = Message.obtain();
+ m.what = PipMenuActivityController.MESSAGE_ACTIVITY_VISIBILITY_CHANGED;
+ m.arg1 = visible ? 1 : 0;
+ m.replyTo = visible ? mMessenger : null;
+ try {
+ mToControllerMessenger.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not notify controller of PIP menu visibility", e);
+ }
+ }
+
+ private void notifyExpandPip() {
+ Message m = Message.obtain();
+ m.what = PipMenuActivityController.MESSAGE_EXPAND_PIP;
+ try {
+ mToControllerMessenger.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not notify controller to expand PIP", e);
+ }
+ }
+
+ private void repostDelayedFinish(long delay) {
+ View v = getWindow().getDecorView();
+ v.removeCallbacks(mFinishRunnable);
+ v.postDelayed(mFinishRunnable, delay);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
new file mode 100644
index 000000000000..d1bce0c74ccd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -0,0 +1,126 @@
+package com.android.systemui.pip.phone;
+
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+
+import android.app.ActivityManager.StackInfo;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.IWindowManager;
+
+import java.util.ArrayList;
+
+public class PipMenuActivityController {
+
+ private static final String TAG = "PipMenuActivityController";
+
+ public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
+ public static final int MESSAGE_ACTIVITY_VISIBILITY_CHANGED = 1;
+ public static final int MESSAGE_EXPAND_PIP = 3;
+
+ /**
+ * A listener interface to receive notification on changes in PIP.
+ */
+ public interface Listener {
+ /**
+ * Called when the PIP menu visibility changes.
+ */
+ void onPipMenuVisibilityChanged(boolean visible);
+ }
+
+ private Context mContext;
+ private IActivityManager mActivityManager;
+ private IWindowManager mWindowManager;
+ private ArrayList<Listener> mListeners = new ArrayList<>();
+
+ private Messenger mToActivityMessenger;
+ private Messenger mMessenger = new Messenger(new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_ACTIVITY_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;
+ break;
+ }
+ case MESSAGE_EXPAND_PIP: {
+ try {
+ mActivityManager.resizeStack(PINNED_STACK_ID, null, true, true, true, 225);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error showing PIP menu activity", e);
+ }
+ break;
+ }
+ }
+ }
+ });
+
+ public PipMenuActivityController(Context context, IActivityManager activityManager,
+ IWindowManager windowManager) {
+ mContext = context;
+ mActivityManager = activityManager;
+ mWindowManager = windowManager;
+ }
+
+ /**
+ * Adds a new menu activity listener.
+ */
+ public void addListener(Listener listener) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener);
+ }
+ }
+
+ /**
+ * 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);
+ 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");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error showing PIP menu activity", e);
+ }
+ }
+
+ /**
+ * Hides the menu activity.
+ */
+ public void hideMenu() {
+ if (mToActivityMessenger != null) {
+ Message m = Message.obtain();
+ m.what = PipMenuActivity.MESSAGE_FINISH_SELF;
+ try {
+ mToActivityMessenger.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not notify menu activity to finish", 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 e32022abdf38..a3593806fb1f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -32,6 +32,7 @@ import android.app.IActivityManager;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -61,6 +62,8 @@ public class PipTouchHandler implements TunerService.Tunable {
private static final String TUNER_KEY_SWIPE_TO_DISMISS = "pip_swipe_to_dismiss";
private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
+ private static final String TUNER_KEY_TAP_THROUGH = "pip_tap_through";
+ private static final String TUNER_KEY_SNAP_MODE_EDGE = "pip_snap_mode_edge";
private static final int SNAP_STACK_DURATION = 225;
private static final int DISMISS_STACK_DURATION = 375;
@@ -70,17 +73,20 @@ public class PipTouchHandler implements TunerService.Tunable {
private final IActivityManager mActivityManager;
private final IWindowManager mWindowManager;
private final ViewConfiguration mViewConfig;
- private final InputChannel mInputChannel = new InputChannel();
private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
+ private final PipMenuListener mMenuListener = new PipMenuListener();
private IPinnedStackController mPinnedStackController;
- private final PipInputEventReceiver mInputEventReceiver;
+ private PipInputEventReceiver mInputEventReceiver;
+ private PipMenuActivityController mMenuController;
private PipDismissViewController mDismissViewController;
private final PipSnapAlgorithm mSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private boolean mEnableSwipeToDismiss = true;
private boolean mEnableDragToDismiss = true;
+ private boolean mEnableTapThrough = false;
+ private boolean mEnableSnapToEdge = false;
private final Rect mPinnedStackBounds = new Rect();
private final Rect mBoundedPinnedStackBounds = new Rect();
@@ -97,6 +103,7 @@ public class PipTouchHandler implements TunerService.Tunable {
private final PointF mLastTouch = new PointF();
private boolean mIsDragging;
private boolean mIsSwipingToDismiss;
+ private boolean mIsTappingThrough;
private int mActivePointerId;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -120,7 +127,7 @@ public class PipTouchHandler implements TunerService.Tunable {
// To be implemented for input handling over Pip windows
if (event instanceof MotionEvent) {
MotionEvent ev = (MotionEvent) event;
- handleTouchEvent(ev);
+ handled = handleTouchEvent(ev);
}
} finally {
finishInputEvent(event, handled);
@@ -144,13 +151,26 @@ public class PipTouchHandler implements TunerService.Tunable {
}
}
- public PipTouchHandler(Context context, IActivityManager activityManager,
- IWindowManager windowManager) {
+ /**
+ * A listener for the PIP menu activity.
+ */
+ private class PipMenuListener implements PipMenuActivityController.Listener {
+ @Override
+ public void onPipMenuVisibilityChanged(boolean visible) {
+ if (!visible) {
+ mIsTappingThrough = false;
+ registerInputConsumer();
+ } else {
+ unregisterInputConsumer();
+ }
+ }
+ }
+
+ public PipTouchHandler(Context context, PipMenuActivityController menuController,
+ IActivityManager activityManager, IWindowManager windowManager) {
// Initialize the Pip input consumer
try {
- windowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
- windowManager.createInputConsumer(INPUT_CONSUMER_PIP, mInputChannel);
windowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
} catch (RemoteException e) {
Log.e(TAG, "Failed to create PIP input consumer", e);
@@ -159,22 +179,29 @@ public class PipTouchHandler implements TunerService.Tunable {
mActivityManager = activityManager;
mWindowManager = windowManager;
mViewConfig = ViewConfiguration.get(context);
- mInputEventReceiver = new PipInputEventReceiver(mInputChannel, Looper.myLooper());
- if (mEnableDragToDismiss) {
- mDismissViewController = new PipDismissViewController(context);
- }
+ mMenuController = menuController;
+ mMenuController.addListener(mMenuListener);
+ mDismissViewController = new PipDismissViewController(context);
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler());
+ registerInputConsumer();
// Register any tuner settings changes
TunerService.get(context).addTunable(this, TUNER_KEY_SWIPE_TO_DISMISS,
- TUNER_KEY_DRAG_TO_DISMISS);
+ TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE);
}
@Override
public void onTuningChanged(String key, String newValue) {
if (newValue == null) {
+ // Reset back to default
+ mEnableSwipeToDismiss = true;
+ mEnableDragToDismiss = true;
+ mEnableTapThrough = false;
+ mIsTappingThrough = false;
+ mEnableSnapToEdge = false;
+ setSnapToEdge(false);
return;
}
switch (key) {
@@ -184,6 +211,14 @@ public class PipTouchHandler implements TunerService.Tunable {
case TUNER_KEY_DRAG_TO_DISMISS:
mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
break;
+ case TUNER_KEY_TAP_THROUGH:
+ mEnableTapThrough = Integer.parseInt(newValue) != 0;
+ mIsTappingThrough = false;
+ break;
+ case TUNER_KEY_SNAP_MODE_EDGE:
+ mEnableSnapToEdge = Integer.parseInt(newValue) != 0;
+ setSnapToEdge(mEnableSnapToEdge);
+ break;
}
}
@@ -192,10 +227,10 @@ public class PipTouchHandler implements TunerService.Tunable {
updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
}
- private void handleTouchEvent(MotionEvent ev) {
+ private boolean handleTouchEvent(MotionEvent ev) {
// Skip touch handling until we are bound to the controller
if (mPinnedStackController == null) {
- return;
+ return true;
}
switch (ev.getAction()) {
@@ -239,6 +274,8 @@ public class PipTouchHandler implements TunerService.Tunable {
float movement = PointF.length(mDownTouch.x - x, mDownTouch.y - y);
if (movement > mViewConfig.getScaledTouchSlop()) {
mIsDragging = true;
+ mIsTappingThrough = false;
+ mMenuController.hideMenu();
if (mEnableSwipeToDismiss) {
// TODO: this check can have some buffer so that we only start swiping
// after a significant move out of bounds
@@ -328,7 +365,14 @@ public class PipTouchHandler implements TunerService.Tunable {
}
}
} else {
- expandPinnedStackToFullscreen();
+ if (mEnableTapThrough) {
+ if (!mIsTappingThrough) {
+ mMenuController.showMenu();
+ mIsTappingThrough = true;
+ }
+ } else {
+ expandPinnedStackToFullscreen();
+ }
}
if (mEnableDragToDismiss) {
mDismissViewController.destroyDismissTarget();
@@ -348,6 +392,7 @@ public class PipTouchHandler implements TunerService.Tunable {
break;
}
}
+ return !mIsTappingThrough;
}
private void initOrResetVelocityTracker() {
@@ -366,6 +411,44 @@ 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);
+ }
+ 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);
+ }
+ mInputEventReceiver.dispose();
+ }
+
+ /**
+ * Sets the snap-to-edge state.
+ */
+ private void setSnapToEdge(boolean snapToEdge) {
+ mSnapAlgorithm.setSnapToEdge(snapToEdge);
+ try {
+ mPinnedStackController.setSnapToEdge(snapToEdge);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not set snap mode to edge", e);
+ }
+ }
+
+ /**
* Flings the PIP to the closest snap target.
*/
private void flingToSnapTarget(float velocity, float velocityX, float velocityY) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index faca8db3ab87..1ccf7229cc87 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -99,6 +99,13 @@ class PinnedStackController {
mInInteractiveMode = inInteractiveMode;
});
}
+
+ @Override
+ public void setSnapToEdge(final boolean snapToEdge) {
+ mHandler.post(() -> {
+ mSnapAlgorithm.setSnapToEdge(snapToEdge);
+ });
+ }
}
/**