Add faster emergency dialer UI
If flag "faster_emergency_phone_call_enabled" is true, EmergencyDialer
will display emergency dialer shortcuts UI. Otherwise, EmergencyDialer
display original dialer UI.
Faster emergency dialer implement the part of user's Emergency
Infomation, and a button which is used to show dialpad.
Test: Manually
Bug: 80406570
Change-Id: I3637dab0059d6fa87417bb282163ebff04eae71d
Merged-In: I3637dab0059d6fa87417bb282163ebff04eae71d
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index b647623..d72c265 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -22,11 +22,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.Layout;
import android.text.TextUtils;
@@ -125,15 +121,13 @@
mPendingTouchEvent = null;
}
-
-
private void setupAssistActions() {
int[] buttonIds = new int[] {R.id.action1, R.id.action2, R.id.action3};
List<ResolveInfo> infos;
if (TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED) {
- infos = resolveAssistPackageAndQueryActivites();
+ infos = EmergencyAssistanceHelper.resolveAssistPackageAndQueryActivities(getContext());
} else {
infos = null;
}
@@ -146,7 +140,7 @@
if (infos != null && infos.size() > i && infos.get(i) != null) {
ResolveInfo info = infos.get(i);
- ComponentName name = getComponentName(info);
+ ComponentName name = EmergencyAssistanceHelper.getComponentName(info);
button.setTag(R.id.tag_intent,
new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
@@ -159,69 +153,6 @@
}
}
- private List<ResolveInfo> resolveAssistPackageAndQueryActivites() {
- List<ResolveInfo> infos = queryAssistActivities();
-
- if (infos == null || infos.isEmpty()) {
- PackageManager packageManager = getContext().getPackageManager();
- Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
- infos = packageManager.queryIntentActivities(queryIntent, 0);
-
- PackageInfo bestMatch = null;
- for (int i = 0; i < infos.size(); i++) {
- if (infos.get(i).activityInfo == null) continue;
- String packageName = infos.get(i).activityInfo.packageName;
- PackageInfo packageInfo;
- try {
- packageInfo = packageManager.getPackageInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- continue;
- }
- // Get earliest installed system app.
- if (isSystemApp(packageInfo) && (bestMatch == null ||
- bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
- bestMatch = packageInfo;
- }
- }
-
- if (bestMatch != null) {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
- bestMatch.packageName);
- return queryAssistActivities();
- } else {
- return null;
- }
- } else {
- return infos;
- }
- }
-
- private List<ResolveInfo> queryAssistActivities() {
- String assistPackage = Settings.Secure.getString(
- getContext().getContentResolver(),
- Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
- List<ResolveInfo> infos = null;
-
- if (!TextUtils.isEmpty(assistPackage)) {
- Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
- .setPackage(assistPackage);
- infos = getContext().getPackageManager().queryIntentActivities(queryIntent, 0);
- }
- return infos;
- }
-
- private boolean isSystemApp(PackageInfo info) {
- return info.applicationInfo != null
- && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- }
-
- private ComponentName getComponentName(ResolveInfo resolveInfo) {
- if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
- return new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name);
- }
-
@Override
public void onClick(View v) {
Intent intent = (Intent) v.getTag(R.id.tag_intent);
@@ -405,6 +336,4 @@
startRipple();
}
};
-
-
}
diff --git a/src/com/android/phone/EmergencyAssistanceHelper.java b/src/com/android/phone/EmergencyAssistanceHelper.java
new file mode 100644
index 0000000..3053125
--- /dev/null
+++ b/src/com/android/phone/EmergencyAssistanceHelper.java
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+package com.android.phone;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import java.util.List;
+
+/**
+ * A helper to query activities of emergency assistance.
+ */
+public class EmergencyAssistanceHelper {
+
+ /**
+ * Query activities of emergency assistance.
+ *
+ * @param context The context of the application.
+ * @return A list of {@link ResolveInfo} which is queried from default assistance package,
+ * or null if there is no installed system application of emergency assistance.
+ */
+ public static List<ResolveInfo> resolveAssistPackageAndQueryActivities(Context context) {
+ List<ResolveInfo> infos = queryAssistActivities(context);
+
+ if (infos == null || infos.isEmpty()) {
+ PackageManager packageManager = context.getPackageManager();
+ Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+ infos = packageManager.queryIntentActivities(queryIntent, 0);
+
+ PackageInfo bestMatch = null;
+ for (int i = 0; i < infos.size(); i++) {
+ if (infos.get(i).activityInfo == null) continue;
+ String packageName = infos.get(i).activityInfo.packageName;
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ continue;
+ }
+ // Get earliest installed system app.
+ if (isSystemApp(packageInfo) && (bestMatch == null
+ || bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
+ bestMatch = packageInfo;
+ }
+ }
+
+ if (bestMatch != null) {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, bestMatch.packageName);
+ return queryAssistActivities(context);
+ } else {
+ return null;
+ }
+ } else {
+ return infos;
+ }
+ }
+
+ /**
+ * Compose {@link ComponentName} from {@link ResolveInfo}.
+ */
+ public static ComponentName getComponentName(ResolveInfo resolveInfo) {
+ if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+
+ private static List<ResolveInfo> queryAssistActivities(Context context) {
+ final String assistPackage = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION);
+ List<ResolveInfo> infos = null;
+
+ if (!TextUtils.isEmpty(assistPackage)) {
+ Intent queryIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
+ .setPackage(assistPackage);
+ infos = context.getPackageManager().queryIntentActivities(queryIntent, 0);
+ }
+ return infos;
+ }
+
+ private static boolean isSystemApp(PackageInfo info) {
+ return info.applicationInfo != null
+ && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+}
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 157cf1d..70ee5d6 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -18,6 +18,8 @@
import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -81,6 +83,13 @@
* moved into a shared base class that would live in the framework?
* Or could we figure out some way to move *this* class into apps/Contacts
* also?
+ *
+ * TODO: Implement emergency dialer shortcut.
+ * emergency dialer shortcut offer a local emergency number list. Directly click a number to
+ * make an emergency phone call without entering numbers from dialpad.
+ * TODO item:
+ * 1.implement emergency shortcut list UI.
+ * 2.integrate emergency phone number table.
*/
public class EmergencyDialer extends Activity implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener, TextWatcher,
@@ -119,6 +128,8 @@
ResizingTextEditText mDigits;
private View mDialButton;
private View mDelete;
+ private View mEmergencyShortcutView;
+ private View mDialpadView;
private ToneGenerator mToneGenerator;
private Object mToneGeneratorLock = new Object();
@@ -148,6 +159,8 @@
private boolean mIsWfcEmergencyCallingWarningEnabled;
private float mDefaultDigitsTextSize;
+ private boolean mAreEmergencyDialerShortcutsEnabled;
+
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
@@ -273,6 +286,13 @@
registerReceiver(mBroadcastReceiver, intentFilter);
mEmergencyActionGroup = (EmergencyActionGroup) findViewById(R.id.emergency_action_group);
+
+ mAreEmergencyDialerShortcutsEnabled = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
+
+ if (mAreEmergencyDialerShortcutsEnabled) {
+ setupEmergencyShortcutsView();
+ }
}
@Override
@@ -328,6 +348,19 @@
view.setOnLongClickListener(this);
}
+ @Override
+ public void onBackPressed() {
+ // If emergency dialer shortcut is enabled and Dialpad view is visible, pressing the
+ // back key will back to display FasterEmergencyDialer view.
+ // Otherwise, it would finish the activity.
+ if (mAreEmergencyDialerShortcutsEnabled && mDialpadView != null
+ && mDialpadView.getVisibility() == View.VISIBLE) {
+ switchView(mEmergencyShortcutView, mDialpadView, true);
+ return;
+ }
+ super.onBackPressed();
+ }
+
/**
* handle key events
*/
@@ -399,6 +432,17 @@
}
return;
}
+ case R.id.floating_action_button_dialpad: {
+ switchView(mDialpadView, mEmergencyShortcutView, true);
+ return;
+ }
+ case R.id.emergency_info_button: {
+ Intent intent = (Intent) view.getTag(R.id.tag_intent);
+ if (intent != null) {
+ startActivity(intent);
+ }
+ return;
+ }
}
}
@@ -792,4 +836,77 @@
Log.i(LOG_TAG, "hint - setting to " + mDigits.getScaledTextSize());
}
}
+
+ private void setupEmergencyShortcutsView() {
+ mEmergencyShortcutView = findViewById(R.id.emergency_dialer_shortcuts);
+ mDialpadView = findViewById(R.id.emergency_dialer);
+
+ final View dialpadButton = findViewById(R.id.floating_action_button_dialpad);
+ dialpadButton.setOnClickListener(this);
+
+ final View emergencyInfoButton = findViewById(R.id.emergency_info_button);
+ emergencyInfoButton.setOnClickListener(this);
+
+ // EmergencyActionGroup is replaced by EmergencyInfoGroup.
+ mEmergencyActionGroup.setVisibility(View.GONE);
+
+ // Setup dialpad title.
+ final View emergencyDialpadTitle = findViewById(R.id.emergency_dialpad_title_container);
+ emergencyDialpadTitle.setVisibility(View.VISIBLE);
+
+ switchView(mEmergencyShortcutView, mDialpadView, false);
+ }
+
+ /**
+ * Switch two view.
+ *
+ * @param displayView the view would be displayed.
+ * @param hideView the view would be hidden.
+ * @param hasAnimation is {@code true} when the view should be displayed with animation.
+ */
+ private void switchView(View displayView, View hideView, boolean hasAnimation) {
+ if (displayView == null || hideView == null) {
+ return;
+ }
+
+ if (displayView.getVisibility() == View.VISIBLE) {
+ return;
+ }
+
+ if (hasAnimation) {
+ crossfade(hideView, displayView);
+ } else {
+ hideView.setVisibility(View.GONE);
+ displayView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Fade out and fade in animation between two view transition.
+ */
+ private void crossfade(View fadeOutView, View fadeInView) {
+ if (fadeOutView == null || fadeInView == null) {
+ return;
+ }
+ final int shortAnimationDuration = getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+
+ fadeInView.setAlpha(0f);
+ fadeInView.setVisibility(View.VISIBLE);
+
+ fadeInView.animate()
+ .alpha(1f)
+ .setDuration(shortAnimationDuration)
+ .setListener(null);
+
+ fadeOutView.animate()
+ .alpha(0f)
+ .setDuration(shortAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fadeOutView.setVisibility(View.GONE);
+ }
+ });
+ }
}
diff --git a/src/com/android/phone/EmergencyInfoGroup.java b/src/com/android/phone/EmergencyInfoGroup.java
new file mode 100644
index 0000000..8100a5a
--- /dev/null
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+package com.android.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.TelephonyManager;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.internal.util.UserIcons;
+
+import java.util.List;
+
+/**
+ * EmergencyInfoGroup display user icon and user name. And it is an entry point to
+ * Emergency Information.
+ */
+public class EmergencyInfoGroup extends LinearLayout {
+
+ private ImageView mEmergencyInfoImage;
+ private TextView mEmergencyInfoName;
+ private View mEmergencyInfoTitle;
+ private View mEmergencyInfoButton;
+
+ public EmergencyInfoGroup(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mEmergencyInfoTitle = findViewById(R.id.emergency_info_title);
+ mEmergencyInfoButton = findViewById(R.id.emergency_info_button);
+ mEmergencyInfoImage = (ImageView) findViewById(R.id.emergency_info_image);
+ mEmergencyInfoName = (TextView) findViewById(R.id.emergency_info_name);
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ setupButtonInfo();
+ }
+ }
+
+ private void setupButtonInfo() {
+ List<ResolveInfo> infos;
+
+ if (TelephonyManager.EMERGENCY_ASSISTANCE_ENABLED) {
+ infos = EmergencyAssistanceHelper.resolveAssistPackageAndQueryActivities(getContext());
+ } else {
+ infos = null;
+ }
+
+ boolean visible = false;
+
+ if (infos != null && infos.size() > 0) {
+ final String packageName = infos.get(0).activityInfo.packageName;
+ final Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE)
+ .setPackage(packageName);
+ mEmergencyInfoButton.setTag(R.id.tag_intent, intent);
+ mEmergencyInfoImage.setImageDrawable(getCircularUserIcon());
+
+ /* TODO: Get user name.
+ if user name exist:
+ 1. mEmergencyInfoTitle show title.
+ 2. mEmergencyInfoName show user name.
+ if user name does not exist:
+ 1. mEmergencyInfoTitle hide.
+ 2. mEmergencyInfoName show app label. */
+ mEmergencyInfoTitle.setVisibility(View.INVISIBLE);
+ mEmergencyInfoName.setText(getContext().getResources().getString(
+ R.string.emergency_information_title));
+
+ visible = true;
+ }
+
+ setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ private Drawable getCircularUserIcon() {
+ final UserManager userManager = (UserManager) getContext().getSystemService(
+ Context.USER_SERVICE);
+ Bitmap bitmapUserIcon = userManager.getUserIcon(UserHandle.getCallingUserId());
+
+ if (bitmapUserIcon == null) {
+ // get default user icon.
+ final Drawable defaultUserIcon = UserIcons.getDefaultUserIcon(
+ getContext().getResources(), UserHandle.getCallingUserId(), false);
+ bitmapUserIcon = UserIcons.convertToBitmap(defaultUserIcon);
+ }
+
+ RoundedBitmapDrawable drawableUserIcon = RoundedBitmapDrawableFactory.create(
+ getContext().getResources(), bitmapUserIcon);
+ drawableUserIcon.setCircular(true);
+
+ return drawableUserIcon;
+ }
+}