diff options
| -rw-r--r-- | core/java/android/app/AlertDialog.java | 19 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/AlertController.java | 27 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 5 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 1 | ||||
| -rw-r--r-- | packages/SystemUI/res/values/strings.xml | 2 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java | 100 |
6 files changed, 148 insertions, 6 deletions
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index a44bd0305875..07b4b9c39e1e 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.database.Cursor; 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 @@ import com.android.internal.R; * </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 @@ public class AlertDialog extends Dialog implements DialogInterface { 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 46cb5461b682..732172111b80 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.database.Cursor; 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 @@ public class AlertController { 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 class AlertController { } } + 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 @@ public class AlertController { 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 395b26935838..e5bb587cddf4 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 6721f93e016c..2bb44763f4ce 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 d82b00c316a8..697ab06afb19 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 d860fc52b97c..c6bb17c2d133 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 @@ package com.android.systemui.power; 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 com.android.systemui.util.NotificationChannels; 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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; |