DO NOT MERGE Make "Want to start battery saver?" dialog better.
- Don't line-break in "Battery" (only in English)
- Add "Learn more" link.
Bug: 78261259
Test: Manual test with:
- adb shell dumpsys battery unplug
- adb shell settings delete secure low_power_warning_acknowledged
- Enable battery saver
- Make sure the link is clickable if a link is set.
- Make sure there's no "learn more" link if the link is not set in strings.xml
Change-Id: I83364f628dd596a4d50bf2aca4db7cbfe7cf4909
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index a44bd03..07b4b9c 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -16,8 +16,6 @@
package android.app;
-import com.android.internal.app.AlertController;
-
import android.annotation.ArrayRes;
import android.annotation.AttrRes;
import android.annotation.DrawableRes;
@@ -30,17 +28,19 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Message;
+import android.text.Layout;
+import android.text.method.MovementMethod;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
-import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.android.internal.R;
+import com.android.internal.app.AlertController;
/**
* A subclass of Dialog that can display one, two or three buttons. If you only want to
@@ -54,7 +54,7 @@
* </pre>
*
* <p>The AlertDialog class takes care of automatically setting
- * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
+ * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
* WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
* any views in the dialog return true from {@link View#onCheckIsTextEditor()
* View.onCheckIsTextEditor()}. Generally you want this set for a Dialog
@@ -266,6 +266,17 @@
mAlert.setMessage(message);
}
+ /** @hide */
+ public void setMessageMovementMethod(MovementMethod movementMethod) {
+ mAlert.setMessageMovementMethod(movementMethod);
+ }
+
+ /** @hide */
+ public void setMessageHyphenationFrequency(
+ @Layout.HyphenationFrequency int hyphenationFrequency) {
+ mAlert.setMessageHyphenationFrequency(hyphenationFrequency);
+ }
+
/**
* Set the view to display in that dialog.
*/
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 46cb546..7321721 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -30,7 +30,10 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
+import android.text.Layout;
import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
@@ -101,6 +104,9 @@
private ImageView mIconView;
private TextView mTitleView;
protected TextView mMessageView;
+ private MovementMethod mMessageMovementMethod;
+ @Layout.HyphenationFrequency
+ private Integer mMessageHyphenationFrequency;
private View mCustomTitleView;
private boolean mForceInverseBackground;
@@ -290,6 +296,21 @@
}
}
+ public void setMessageMovementMethod(MovementMethod movementMethod) {
+ mMessageMovementMethod = movementMethod;
+ if (mMessageView != null) {
+ mMessageView.setMovementMethod(movementMethod);
+ }
+ }
+
+ public void setMessageHyphenationFrequency(
+ @Layout.HyphenationFrequency int hyphenationFrequency) {
+ mMessageHyphenationFrequency = hyphenationFrequency;
+ if (mMessageView != null) {
+ mMessageView.setHyphenationFrequency(hyphenationFrequency);
+ }
+ }
+
/**
* Set the view resource to display in the dialog.
*/
@@ -676,6 +697,12 @@
if (mMessage != null) {
mMessageView.setText(mMessage);
+ if (mMessageMovementMethod != null) {
+ mMessageView.setMovementMethod(mMessageMovementMethod);
+ }
+ if (mMessageHyphenationFrequency != null) {
+ mMessageView.setHyphenationFrequency(mMessageHyphenationFrequency);
+ }
} else {
mMessageView.setVisibility(View.GONE);
mScrollView.removeView(mMessageView);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 395b269..e5bb587 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4514,7 +4514,10 @@
<!-- Notification shown when device owner silently deletes a package [CHAR LIMIT=NONE] -->
<string name="package_deleted_device_owner">Deleted by your admin</string>
- <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
+ <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, with a "learn more" link. -->
+ <string name="battery_saver_description_with_learn_more">To extend your battery life, Battery Saver turns off some device features and restricts apps. <annotation id="url">Learn More</annotation></string>
+
+ <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, without a "learn more" link. -->
<string name="battery_saver_description">To extend your battery life, Battery Saver turns off some device features and restricts apps.</string>
<!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6721f93..2bb4476 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3369,4 +3369,5 @@
<java-symbol type="id" name="user_loading_avatar" />
<java-symbol type="id" name="user_loading" />
+ <java-symbol type="string" name="battery_saver_description_with_learn_more" />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d82b00c..697ab06 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2223,4 +2223,6 @@
<!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: user acknowledges and closes the dialog. [CHAR LIMIT=NONE]-->
<string name="auto_saver_okay_action">Got it</string>
+ <!-- URl of the webpage that explains battery saver. -->
+ <string name="help_uri_battery_saver_learn_more_link_target" translatable="false"></string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index d860fc5..c6bb17c 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -19,17 +19,29 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
+import android.text.Annotation;
+import android.text.Layout;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.text.style.URLSpan;
+import android.util.Log;
import android.util.Slog;
+import android.view.View;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.settingslib.Utils;
@@ -42,6 +54,8 @@
import java.io.PrintWriter;
import java.text.NumberFormat;
+import java.util.Locale;
+import java.util.Objects;
public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String TAG = PowerUI.TAG + ".Notification";
@@ -87,6 +101,8 @@
private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING =
"android.settings.BATTERY_SAVER_SETTINGS";
+ private static final String BATTERY_SAVER_DESCRIPTION_URL_KEY = "url";
+
private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
@@ -461,7 +477,16 @@
if (mSaverConfirmation != null) return;
final SystemUIDialog d = new SystemUIDialog(mContext);
d.setTitle(R.string.battery_saver_confirmation_title);
- d.setMessage(com.android.internal.R.string.battery_saver_description);
+ d.setMessage(getBatterySaverDescription());
+
+ // Sad hack for http://b/78261259 and http://b/78298335. Otherwise "Battery" may be split
+ // into "Bat-tery".
+ if (isEnglishLocale()) {
+ d.setMessageHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
+ }
+ // We need to set LinkMovementMethod to make the link clickable.
+ d.setMessageMovementMethod(LinkMovementMethod.getInstance());
+
d.setNegativeButton(android.R.string.cancel, null);
d.setPositiveButton(R.string.battery_saver_confirmation_ok,
(dialog, which) -> setSaverMode(true, false));
@@ -471,6 +496,79 @@
mSaverConfirmation = d;
}
+ private boolean isEnglishLocale() {
+ return Objects.equals(Locale.getDefault().getLanguage(),
+ Locale.ENGLISH.getLanguage());
+ }
+
+ /**
+ * Generates the message for the "want to start battery saver?" dialog with a "learn more" link.
+ */
+ private CharSequence getBatterySaverDescription() {
+ final String learnMoreUrl = mContext.getText(
+ R.string.help_uri_battery_saver_learn_more_link_target).toString();
+
+ // If there's no link, use the string with no "learn more".
+ if (TextUtils.isEmpty(learnMoreUrl)) {
+ return mContext.getText(
+ com.android.internal.R.string.battery_saver_description);
+ }
+
+ // If we have a link, use the string with the "learn more" link.
+ final CharSequence rawText = mContext.getText(
+ com.android.internal.R.string.battery_saver_description_with_learn_more);
+ final SpannableString message = new SpannableString(rawText);
+ final SpannableStringBuilder builder = new SpannableStringBuilder(message);
+
+ // Look for the "learn more" part of the string, and set a URL span on it.
+ // We use a customized URLSpan to add FLAG_RECEIVER_FOREGROUND to the intent, and
+ // also to close the dialog.
+ for (Annotation annotation : message.getSpans(0, message.length(), Annotation.class)) {
+ final String key = annotation.getValue();
+
+ if (!BATTERY_SAVER_DESCRIPTION_URL_KEY.equals(key)) {
+ continue;
+ }
+ final int start = message.getSpanStart(annotation);
+ final int end = message.getSpanEnd(annotation);
+
+ // Replace the "learn more" with a custom URL span, with
+ // - No underline.
+ // - When clicked, close the dialog and the notification shade.
+ final URLSpan urlSpan = new URLSpan(learnMoreUrl) {
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ super.updateDrawState(ds);
+ ds.setUnderlineText(false);
+ }
+
+ @Override
+ public void onClick(View widget) {
+ // Close the parent dialog.
+ if (mSaverConfirmation != null) {
+ mSaverConfirmation.dismiss();
+ }
+ // Also close the notification shade, if it's open.
+ mContext.sendBroadcast(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
+
+ final Uri uri = Uri.parse(getURL());
+ Context context = widget.getContext();
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Activity was not found for intent, " + intent.toString());
+ }
+ }
+ };
+ builder.setSpan(urlSpan, start, end, message.getSpanFlags(urlSpan));
+ }
+ return builder;
+ }
+
private void showAutoSaverEnabledConfirmation() {
if (mSaverEnabledConfirmation != null) return;