Add separated emergency option on power menu

- Add a separated button on power menu to launch emergency dialer.
 - Change HardwareUiLayout.java FrameLayout to LinearLayout, let it can
display separated button.
 - Add a flag to recognize separated button should show/hide, if
EmergencyAffordance(India) enabled, separated button will hide,
otherwise power menu will display separated button & power
menu last item won't get white background.

Test: Manually, use "adb shell settings put global faster_emergency_phone_call_enabled 1" to show/hide separated emergency option, press emergency option will go to emergency dialer.
Bug: 80376488
Change-Id: I8e6bb72ce7b8cecdb6bd01150b53f61f1515dbb1
This commit is contained in:
Wesley.CW Wang
2018-06-15 16:24:57 +08:00
parent 8d07276f23
commit 3004fcb949
6 changed files with 135 additions and 18 deletions

View File

@@ -2565,8 +2565,8 @@
<item>lockdown</item>
<item>logout</item>
<item>bugreport</item>
<item>emergency</item>
<item>screenshot</item>
<item>emergency</item>
</string-array>
<!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully

View File

@@ -0,0 +1,30 @@
<!--
Copyright (C) 2018 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.
-->
<!-- TODO: For demo only, will change content after UI team provide new faster emergency icon. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#D93025"
android:pathData="M0,0h24v24H0z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,3H5c-1.1,0-1.99,0.9,-1.99,2L3,19c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2zm-1,11h-4v4h-4v-4H6v-4h4V6h4v4h4v4z" />
</vector>

View File

@@ -3,7 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|right"
android:layout_marginBottom="0dp"
android:orientation="vertical"
android:paddingTop="@dimen/global_actions_top_padding"
android:clipToPadding="false"
android:theme="@style/qs_theme"
@@ -17,7 +19,19 @@
android:layout_gravity="top|right"
android:gravity="center"
android:orientation="vertical"
android:padding="12dp"
android:translationZ="9dp" />
android:padding="@dimen/global_actions_padding"
android:translationZ="@dimen/global_actions_translate" />
<!-- For separated button-->
<FrameLayout
android:id="@+id/separated_button"
android:layout_width="@dimen/global_actions_panel_width"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:layout_marginTop="6dp"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/global_actions_padding"
android:translationZ="@dimen/global_actions_translate" />
</com.android.systemui.HardwareUiLayout>

View File

@@ -920,6 +920,10 @@
<dimen name="global_actions_top_padding">120dp</dimen>
<dimen name="global_actions_padding">12dp</dimen>
<dimen name="global_actions_translate">9dp</dimen>
<!-- the maximum offset in either direction that elements are moved horizontally to prevent
burn-in on AOD -->
<dimen name="burn_in_prevention_offset_x">8dp</dimen>

View File

@@ -27,24 +27,22 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
public class HardwareUiLayout extends FrameLayout implements Tunable {
public class HardwareUiLayout extends LinearLayout implements Tunable {
private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
private final int[] mTmp2 = new int[2];
private View mChild;
private View mSeparatedView;
private int mOldHeight;
private boolean mAnimating;
private AnimatorSet mAnimation;
@@ -53,6 +51,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
private HardwareBgDrawable mBackground;
private Animator mAnimator;
private boolean mCollapse;
private boolean mHasSeparatedButton;
private int mEndPoint;
private boolean mEdgeBleed;
private boolean mRoundedDivider;
@@ -94,6 +93,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
if (mChild != null) {
mChild.setBackground(mBackground);
mSeparatedView.setBackground(mBackground);
requestLayout();
}
}
@@ -110,6 +110,18 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
}
mChild.setLayoutParams(params);
}
if (mSeparatedView != null) {
MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
if (mRotation == ROTATION_LANDSCAPE) {
params.topMargin = edge;
} else if (mRotation == ROTATION_SEASCAPE) {
params.bottomMargin = edge;
} else {
params.rightMargin = edge;
}
mSeparatedView.setLayoutParams(params);
}
}
private int getEdgePadding() {
@@ -123,6 +135,8 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
if (getChildCount() != 0) {
mChild = getChildAt(0);
mChild.setBackground(mBackground);
mSeparatedView = getChildAt(1);
mSeparatedView.setBackground(mBackground);
updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
mOldHeight = mChild.getMeasuredHeight();
mChild.addOnLayoutChangeListener(
@@ -170,6 +184,17 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
} else {
rotateLeft();
}
if (mHasSeparatedButton) {
if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
// Separated view has top margin, so seascape separated view need special rotation,
// not a full left or right rotation.
swapLeftAndTop(mSeparatedView);
} else if (from == ROTATION_LANDSCAPE) {
rotateRight(mSeparatedView);
} else {
rotateLeft(mSeparatedView);
}
}
if (to != ROTATION_NONE) {
if (mChild instanceof LinearLayout) {
mRotatedBackground = true;
@@ -177,8 +202,10 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
LinearLayout linearLayout = (LinearLayout) mChild;
if (mSwapOrientation) {
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
setOrientation(LinearLayout.HORIZONTAL);
}
swapDimens(this.mChild);
swapDimens(mChild);
swapDimens(mSeparatedView);
}
} else {
if (mChild instanceof LinearLayout) {
@@ -187,8 +214,10 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
LinearLayout linearLayout = (LinearLayout) mChild;
if (mSwapOrientation) {
linearLayout.setOrientation(LinearLayout.VERTICAL);
setOrientation(LinearLayout.VERTICAL);
}
swapDimens(mChild);
swapDimens(mSeparatedView);
}
}
}
@@ -201,6 +230,12 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
LayoutParams p = (LayoutParams) mChild.getLayoutParams();
p.gravity = rotateGravityRight(p.gravity);
mChild.setLayoutParams(p);
LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
mSeparatedView.setLayoutParams(separatedViewLayoutParams);
setGravity(p.gravity);
}
private void swapDimens(View v) {
@@ -253,6 +288,12 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
LayoutParams p = (LayoutParams) mChild.getLayoutParams();
p.gravity = rotateGravityLeft(p.gravity);
mChild.setLayoutParams(p);
LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
mSeparatedView.setLayoutParams(separatedViewLayoutParams);
setGravity(p.gravity);
}
private int rotateGravityLeft(int gravity) {
@@ -310,6 +351,15 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
v.setLayoutParams(params);
}
private void swapLeftAndTop(View v) {
v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
v.getPaddingRight());
MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
params.rightMargin);
v.setLayoutParams(params);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -351,6 +401,9 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
private void updatePosition() {
if (mChild == null) return;
// If got separated button, setRotatedBackground to false,
// all items won't get white background.
mBackground.setRotatedBackground(mHasSeparatedButton);
if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
int index = mRotatedBackground ? 0 : 1;
mDivision.getLocationOnScreen(mTmp2);
@@ -404,6 +457,10 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
mCollapse = true;
}
public void setHasSeparatedButton(boolean hasSeparatedButton) {
mHasSeparatedButton = hasSeparatedButton;
}
public static HardwareUiLayout get(View v) {
if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
if (v.getParent() instanceof View) {

View File

@@ -28,12 +28,10 @@ import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Point;
@@ -42,9 +40,7 @@ import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -68,9 +64,9 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
@@ -150,6 +146,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private boolean mDeviceProvisioned = false;
private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
private boolean mIsWaitingForEcmExit = false;
private boolean mHasFasterEmergencyButton;
private boolean mHasTelephony;
private boolean mHasVibrator;
private boolean mHasLogoutButton;
@@ -320,6 +317,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
ArraySet<String> addedKeys = new ArraySet<String>();
mHasLogoutButton = false;
mHasLockdownButton = false;
mHasFasterEmergencyButton = false;
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -363,6 +361,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0
&& !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(new EmergencyAction());
mHasFasterEmergencyButton = true;
}
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
mItems.add(new ScreenshotAction());
@@ -393,7 +392,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
return false;
};
ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener);
ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener,
mHasFasterEmergencyButton);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
dialog.setKeyguardShowing(mKeyguardShowing);
@@ -453,7 +453,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
"com.android.phone.EmergencyDialer.DIAL";
private EmergencyAction() {
super(R.drawable.emergency_icon, R.string.global_action_emergency);
super(com.android.systemui.R.drawable.faster_emergency_icon,
R.string.global_action_emergency);
}
@Override
@@ -1387,15 +1388,17 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final Context mContext;
private final MyAdapter mAdapter;
private final LinearLayout mListView;
private final FrameLayout mSeparatedView;
private final HardwareUiLayout mHardwareLayout;
private final OnClickListener mClickListener;
private final OnItemLongClickListener mLongClickListener;
private final GradientDrawable mGradientDrawable;
private final ColorExtractor mColorExtractor;
private boolean mKeyguardShowing;
private boolean mShouldDisplaySeparatedButton;
public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter,
OnItemLongClickListener longClickListener) {
OnItemLongClickListener longClickListener, boolean shouldDisplaySeparatedButton) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
@@ -1403,6 +1406,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mLongClickListener = longClickListener;
mGradientDrawable = new GradientDrawable(mContext);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mShouldDisplaySeparatedButton = shouldDisplaySeparatedButton;
// Window initialization
Window window = getWindow();
@@ -1426,8 +1430,13 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
setContentView(com.android.systemui.R.layout.global_actions_wrapped);
mListView = findViewById(android.R.id.list);
mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
if (!mShouldDisplaySeparatedButton) {
mSeparatedView.setVisibility(View.GONE);
}
mHardwareLayout = HardwareUiLayout.get(mListView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss());
mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
setTitle(R.string.global_actions);
mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
@@ -1442,13 +1451,16 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private void updateList() {
mListView.removeAllViews();
mSeparatedView.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
View v = mAdapter.getView(i, null, mListView);
ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
? mSeparatedView : mListView;
View v = mAdapter.getView(i, null, parentView);
final int pos = i;
v.setOnClickListener(view -> mClickListener.onClick(this, pos));
v.setOnLongClickListener(view ->
mLongClickListener.onItemLongClick(null, v, pos, 0));
mListView.addView(v);
parentView.addView(v);
}
}