--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+
+ <path
+ android:fillColor="#fff"
+ android:pathData="M7.5,52h45a5,5,0,0,0,5-5V12.95A5,5,0,0,0,52.5,8H7.5a5,5,0,0,0-5,4.95V47A5,5,0,0,0,7.5,52Zm-1-5V13a1,1,0,0,1,1-1h45a1,1,0,0,1,1,1V47a1,1,0,0,1-1,1H7.5A1,1,0,0,1,6.5,47Z" />
+ <path
+ android:pathData="M0,0V60H60V0H0Z" />
+ <path
+ android:fillColor="#fff"
+ android:pathData="M35,39.14v2a1,1,0,0,0,1,1H46.5a1,1,0,0,0,1-1V30.64a1,1,0,0,0-1-1h-2a1,1,0,0,0-1,1v7.5H36A1,1,0,0,0,35,39.14Z" />
+ <path
+ android:fillColor="#fff"
+ android:pathData="M13.5,30.36h2a1,1,0,0,0,1-1v-7.5H24a1,1,0,0,0,1-1v-2a1,1,0,0,0-1-1H13.5a1,1,0,0,0-1,1v10.5A1,1,0,0,0,13.5,30.36Z" />
+</vector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M57.5,47V12.95c0-2.75-2.25-4.95-5-4.95h-45c-2.75,0-5,2.2-5,4.95V47c0,2.75,2.25,5,5,5h45
+C55.25,52,57.5,49.75,57.5,47z
+M52.5,48h-45c-0.55,0-1-0.45-1-1V13c0-0.55,0.45-1,1-1h45c0.55,0,1,0.45,1,1v34
+C53.5,47.55,53.05,48,52.5,48z" />
+ <path
+ android:pathData="M60,0v60H0L0,0L60,0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M25,39.14v2c0,0.55-0.45,1-1,1H13.5c-0.55,0-1-0.45-1-1v-10.5c0-0.55,0.45-1,1-1h2c0.55,0,1,0.45,1,1v7.5
+H24C24.55,38.14,25,38.59,25,39.14z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M46.5,30.36h-2c-0.55,0-1-0.45-1-1v-7.5H36c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h10.5
+c0.55,0,1,0.45,1,1v10.5C47.5,29.91,47.05,30.36,46.5,30.36z" />
+</vector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M47,2.5H12.95C10.2,2.5,8,4.75,8,7.5v45c0,2.75,2.2,5,4.95,5H47c2.75,0,5-2.25,5-5v-45
+C52,4.75,49.75,2.5,47,2.5z
+M48,7.5v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45c0-0.55,0.45-1,1-1h34
+C47.55,6.5,48,6.95,48,7.5z" />
+ <path
+ android:pathData="M0,0l60,0v60H0L0,0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M39.14,35h2c0.55,0,1,0.45,1,1v10.5c0,0.55-0.45,1-1,1h-10.5c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h7.5
+V36C38.14,35.45,38.59,35,39.14,35z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M30.36,13.5v2c0,0.55-0.45,1-1,1h-7.5V24c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V13.5c0-0.55,0.45-1,1-1
+h10.5C29.91,12.5,30.36,12.95,30.36,13.5z" />
+</vector>
\ No newline at end of file
-->
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:padding="10dp"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:padding="@dimen/pip_action_padding"
android:background="?android:selectableItemBackgroundBorderless" />
\ No newline at end of file
android:id="@+id/menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#00000000">
+ android:background="#4D000000">
<!-- The above background is only for the dismiss button ripple to show. -->
<ImageView
android:id="@+id/dismiss"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
android:layout_gravity="top|end"
- android:padding="10dp"
+ android:padding="@dimen/pip_action_padding"
android:contentDescription="@string/pip_phone_close"
android:src="@drawable/ic_close_white"
android:background="?android:selectableItemBackgroundBorderless" />
+ <!-- The margins for this container is calculated in the code depending on whether the
+ actions_container is visible. -->
<FrameLayout
android:id="@+id/expand_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
- android:layout_width="64dp"
- android:layout_height="64dp"
+ android:id="@+id/expand_button"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="@string/pip_phone_expand"
- android:src="@drawable/pip_expand"
android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
<FrameLayout
android:id="@+id/actions_container"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/pip_action_size"
android:layout_gravity="bottom"
- android:background="#66000000"
android:visibility="invisible">
<LinearLayout
android:id="@+id/actions_group"
the configuration of the device, so we can't use -land resources. -->
<dimen name="pip_between_action_padding_land">8dp</dimen>
+ <!-- The height of the PiP actions container in which the actions are vertically centered. -->
+ <dimen name="pip_action_size">48dp</dimen>
+
+ <!-- The padding around a PiP actions. -->
+ <dimen name="pip_action_padding">12dp</dimen>
+
+ <!-- The bottom margin of the expand container when there are actions.
+ Equal to pip_action_size - pip_action_padding. -->
+ <dimen name="pip_expand_container_edge_margin">36dp</dimen>
+
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
package com.android.systemui.pip.phone;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS;
+import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.RemoteAction;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.drawable.Icon;
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.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
private View mMenuContainer;
private LinearLayout mActionsGroup;
private View mDismissButton;
+ private ImageView mExpandButton;
private int mBetweenActionPaddingLand;
private ObjectAnimator mMenuContainerAnimator;
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_SHOW_MENU:
- showMenu();
+ Pair<Rect, Rect> bounds = (Pair<Rect, Rect>) msg.obj;
+ showMenu(bounds.first, bounds.second);
break;
case MESSAGE_POKE_MENU:
cancelDelayedFinish();
hideMenu();
break;
case MESSAGE_UPDATE_ACTIONS:
- setActions(((ParceledListSlice) msg.obj).getList());
+ Pair<Rect, ParceledListSlice> data = (Pair<Rect, ParceledListSlice>) msg.obj;
+ setActions(data.first, data.second.getList());
break;
}
}
super.onCreate(savedInstanceState);
setContentView(R.layout.pip_menu_activity);
- Intent startingIntent = getIntent();
- mToControllerMessenger = startingIntent.getParcelableExtra(
- PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER);
- ParceledListSlice actions = startingIntent.getParcelableExtra(
- PipMenuActivityController.EXTRA_ACTIONS);
- if (actions != null) {
- setActions(actions.getList());
- }
-
mMenuContainer = findViewById(R.id.menu);
mMenuContainer.setOnClickListener((v) -> {
expandPip();
mActionsGroup = (LinearLayout) findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
+ mExpandButton = (ImageView) findViewById(R.id.expand_button);
+ updateFromIntent(getIntent());
notifyActivityCallback(mMessenger);
- showMenu();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
- showMenu();
+ updateFromIntent(intent);
}
@Override
// Do nothing
}
- private void showMenu() {
+ private void showMenu(Rect stackBounds, Rect movementBounds) {
if (!mMenuVisible) {
if (mMenuContainerAnimator != null) {
mMenuContainerAnimator.cancel();
}
notifyMenuVisibility(true);
+ updateExpandButtonFromBounds(stackBounds, movementBounds);
mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
}
}
- private void setActions(List<RemoteAction> actions) {
+ private void updateFromIntent(Intent intent) {
+ Rect stackBounds = Rect.unflattenFromString(intent.getStringExtra(EXTRA_STACK_BOUNDS));
+ Rect movementBounds = Rect.unflattenFromString(intent.getStringExtra(
+ EXTRA_MOVEMENT_BOUNDS));
+ mToControllerMessenger = intent.getParcelableExtra(EXTRA_CONTROLLER_MESSENGER);
+ ParceledListSlice actions = intent.getParcelableExtra(EXTRA_ACTIONS);
+ if (actions != null) {
+ setActions(stackBounds, actions.getList());
+ }
+ showMenu(stackBounds, movementBounds);
+ }
+
+ private void updateExpandButtonFromBounds(Rect stackBounds, Rect movementBounds) {
+ if (stackBounds == null) {
+ return;
+ }
+
+ boolean isLandscapePip = stackBounds.width() > stackBounds.height();
+ boolean left = stackBounds.left < movementBounds.centerX();
+ boolean top = stackBounds.top < movementBounds.centerY();
+ boolean expandL = (left && top) || (!left && !top);
+ int iconResId;
+ if (isLandscapePip) {
+ iconResId = expandL ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
+ } else {
+ iconResId = expandL ? R.drawable.pip_expand_pl : R.drawable.pip_expand_pr;
+ }
+ mExpandButton.setImageResource(iconResId);
+ }
+
+ private void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
- updateActionViews();
+ updateActionViews(stackBounds);
}
- private void updateActionViews() {
+ private void updateActionViews(Rect stackBounds) {
ViewGroup expandContainer = (ViewGroup) findViewById(R.id.expand_container);
ViewGroup actionsContainer = (ViewGroup) findViewById(R.id.actions_container);
actionsContainer.setOnTouchListener((v, ev) -> {
return true;
});
- int actionsContainerHeight = 0;
if (mActions.isEmpty()) {
actionsContainer.setVisibility(View.INVISIBLE);
} else {
mActionsGroup.removeAllViews();
// Recreate the layout
- final View decorView = getWindow().getDecorView();
- final boolean isLandscapePip = decorView.getMeasuredWidth()
- > decorView.getMeasuredHeight();
+ final boolean isLandscapePip = stackBounds != null &&
+ (stackBounds.width() > stackBounds.height());
final LayoutInflater inflater = LayoutInflater.from(this);
for (int i = 0; i < mActions.size(); i++) {
final RemoteAction action = mActions.get(i);
mActionsGroup.addView(actionView);
}
}
- actionsContainerHeight = actionsContainer.getLayoutParams().height;
- }
- // Update the expand container margin to account for the existence of the action container
- ((FrameLayout.LayoutParams) expandContainer.getLayoutParams()).bottomMargin =
- actionsContainerHeight;
- expandContainer.requestLayout();
+ // Update the expand container margin to adjust the center of the expand button to
+ // account for the existence of the action container
+ FrameLayout.LayoutParams expandedLp =
+ (FrameLayout.LayoutParams) expandContainer.getLayoutParams();
+ expandedLp.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_action_padding);
+ expandedLp.bottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_expand_container_edge_margin);
+ expandContainer.requestLayout();
+ }
}
private void notifyRegisterInputConsumer() {
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
+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.util.Pair;
import android.view.IWindowManager;
import com.android.systemui.pip.phone.PipMediaController.ActionListener;
public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
public static final String EXTRA_ACTIONS = "actions";
+ public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
+ public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
public static final int MESSAGE_MENU_VISIBILITY_CHANGED = 100;
public static final int MESSAGE_EXPAND_PIP = 101;
/**
* Shows the menu activity.
*/
- public void showMenu() {
+ public void showMenu(Rect stackBounds, Rect movementBounds) {
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
+ m.obj = new Pair<>(stackBounds, movementBounds);
try {
mToActivityMessenger.send(m);
} catch (RemoteException e) {
Intent intent = new Intent(mContext, PipMenuActivity.class);
intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
+ intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds.flattenToString());
+ intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds.flattenToString());
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
options.setLaunchTaskId(
pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
*/
private void updateMenuActions() {
if (mToActivityMessenger != null) {
+ // Fetch the pinned stack bounds
+ Rect stackBounds = null;
+ try {
+ StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (pinnedStackInfo != null) {
+ stackBounds = pinnedStackInfo.bounds;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error showing PIP menu activity", e);
+ }
+
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
- m.obj = resolveMenuActions();
+ m.obj = new Pair<>(stackBounds, resolveMenuActions());
try {
mToActivityMessenger.send(m);
} catch (RemoteException e) {
// If the menu is still visible, and we aren't minimized, then just poke the menu
// so that it will timeout after the user stops touching it
if (mMenuController.isMenuVisible()) {
- mMenuController.showMenu();
+ mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds);
}
final float velocity = PointF.length(vel.x, vel.y);
mMotionHelper.animateToClosestSnapTarget(mMovementBounds);
setMinimizedStateInternal(false);
} else if (!mIsMenuVisible) {
- mMenuController.showMenu();
+ mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds);
} else {
mMotionHelper.expandPip();
}