diff options
157 files changed, 2858 insertions, 685 deletions
diff --git a/Android.bp b/Android.bp index b9a8dec036f0..82a972aeef84 100644 --- a/Android.bp +++ b/Android.bp @@ -618,6 +618,7 @@ java_library { "android.hardware.vibrator-V1.0-java-constants", "android.hardware.vibrator-V1.1-java-constants", "android.hardware.wifi-V1.0-java-constants", + "android.hardware.radio-V1.0-java", ], // Loaded with System.loadLibrary by android.view.textclassifier diff --git a/Android.mk b/Android.mk index 8199c57bdb5f..3c6dd37acefe 100644 --- a/Android.mk +++ b/Android.mk @@ -829,4 +829,4 @@ ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif -endif # ANDROID_BUILD_EMBEDDED +endif # ANDROID_BUILD_EMBEDDED
\ No newline at end of file diff --git a/api/current.txt b/api/current.txt index be52a83fb8f8..ed0c6a982b70 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5206,15 +5206,17 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; + field public static final java.lang.String EXTRA_MESSAGING_PERSON = "android.messagingUser"; field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"; field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"; - field public static final java.lang.String EXTRA_PEOPLE = "android.people"; + field public static final deprecated java.lang.String EXTRA_PEOPLE = "android.people"; + field public static final java.lang.String EXTRA_PEOPLE_LIST = "android.people.list"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax"; field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; - field public static final java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; + field public static final deprecated java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen"; field public static final deprecated java.lang.String EXTRA_SMALL_ICON = "android.icon"; @@ -5354,7 +5356,8 @@ package android.app { method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Builder addAction(android.app.Notification.Action); method public android.app.Notification.Builder addExtras(android.os.Bundle); - method public android.app.Notification.Builder addPerson(java.lang.String); + method public deprecated android.app.Notification.Builder addPerson(java.lang.String); + method public android.app.Notification.Builder addPerson(android.app.Notification.Person); method public android.app.Notification build(); method public android.widget.RemoteViews createBigContentView(); method public android.widget.RemoteViews createContentView(); @@ -5477,14 +5480,17 @@ package android.app { } public static class Notification.MessagingStyle extends android.app.Notification.Style { - ctor public Notification.MessagingStyle(java.lang.CharSequence); + ctor public deprecated Notification.MessagingStyle(java.lang.CharSequence); + ctor public Notification.MessagingStyle(android.app.Notification.Person); method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message); - method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); + method public deprecated android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); + method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, android.app.Notification.Person); method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); method public java.lang.CharSequence getConversationTitle(); method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages(); method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages(); - method public java.lang.CharSequence getUserDisplayName(); + method public android.app.Notification.Person getUser(); + method public deprecated java.lang.CharSequence getUserDisplayName(); method public boolean isGroupConversation(); method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); method public android.app.Notification.MessagingStyle setGroupConversation(boolean); @@ -5492,16 +5498,34 @@ package android.app { } public static final class Notification.MessagingStyle.Message { - ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); + ctor public deprecated Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); + ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, android.app.Notification.Person); method public java.lang.String getDataMimeType(); method public android.net.Uri getDataUri(); method public android.os.Bundle getExtras(); - method public java.lang.CharSequence getSender(); + method public deprecated java.lang.CharSequence getSender(); + method public android.app.Notification.Person getSenderPerson(); method public java.lang.CharSequence getText(); method public long getTimestamp(); method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri); } + public static final class Notification.Person implements android.os.Parcelable { + ctor protected Notification.Person(android.os.Parcel); + ctor public Notification.Person(); + method public int describeContents(); + method public android.graphics.drawable.Icon getIcon(); + method public java.lang.String getKey(); + method public java.lang.CharSequence getName(); + method public java.lang.String getUri(); + method public android.app.Notification.Person setIcon(android.graphics.drawable.Icon); + method public android.app.Notification.Person setKey(java.lang.String); + method public android.app.Notification.Person setName(java.lang.CharSequence); + method public android.app.Notification.Person setUri(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.Notification.Person> CREATOR; + } + public static abstract class Notification.Style { ctor public Notification.Style(); method public android.app.Notification build(); @@ -41589,6 +41613,78 @@ package android.telephony.cdma { } +package android.telephony.data { + + public class ApnSetting implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getApnName(); + method public int getAuthType(); + method public java.lang.String getEntryName(); + method public int getId(); + method public int getMmsPort(); + method public java.net.InetAddress getMmsProxy(); + method public java.net.URL getMmsc(); + method public java.lang.String getMvnoType(); + method public java.lang.String getOperatorNumeric(); + method public java.lang.String getPassword(); + method public int getPort(); + method public java.lang.String getProtocol(); + method public java.net.InetAddress getProxy(); + method public java.lang.String getRoamingProtocol(); + method public java.util.List<java.lang.String> getTypes(); + method public java.lang.String getUser(); + method public boolean isEnabled(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int AUTH_TYPE_CHAP = 2; // 0x2 + field public static final int AUTH_TYPE_NONE = 0; // 0x0 + field public static final int AUTH_TYPE_PAP = 1; // 0x1 + field public static final int AUTH_TYPE_PAP_OR_CHAP = 3; // 0x3 + field public static final android.os.Parcelable.Creator<android.telephony.data.ApnSetting> CREATOR; + field public static final java.lang.String MVNO_TYPE_GID = "gid"; + field public static final java.lang.String MVNO_TYPE_ICCID = "iccid"; + field public static final java.lang.String MVNO_TYPE_IMSI = "imsi"; + field public static final java.lang.String MVNO_TYPE_SPN = "spn"; + field public static final java.lang.String PROTOCOL_IP = "IP"; + field public static final java.lang.String PROTOCOL_IPV4V6 = "IPV4V6"; + field public static final java.lang.String PROTOCOL_IPV6 = "IPV6"; + field public static final java.lang.String PROTOCOL_PPP = "PPP"; + field public static final java.lang.String TYPE_ALL = "*"; + field public static final java.lang.String TYPE_CBS = "cbs"; + field public static final java.lang.String TYPE_DEFAULT = "default"; + field public static final java.lang.String TYPE_DUN = "dun"; + field public static final java.lang.String TYPE_EMERGENCY = "emergency"; + field public static final java.lang.String TYPE_FOTA = "fota"; + field public static final java.lang.String TYPE_HIPRI = "hipri"; + field public static final java.lang.String TYPE_IA = "ia"; + field public static final java.lang.String TYPE_IMS = "ims"; + field public static final java.lang.String TYPE_MMS = "mms"; + field public static final java.lang.String TYPE_SUPL = "supl"; + } + + public static class ApnSetting.Builder { + ctor public ApnSetting.Builder(); + method public android.telephony.data.ApnSetting build(); + method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setAuthType(int); + method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean); + method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setId(int); + method public android.telephony.data.ApnSetting.Builder setMmsPort(int); + method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL); + method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setPort(int); + method public android.telephony.data.ApnSetting.Builder setProtocol(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setProxy(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setTypes(java.util.List<java.lang.String>); + method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String); + } + +} + package android.telephony.gsm { public class GsmCellLocation extends android.telephony.CellLocation { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 046a128cc81e..a3836048cc7d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1022,10 +1022,18 @@ public class Notification implements Parcelable /** * {@link #extras} key: A String array containing the people that this notification relates to, * each of which was supplied to {@link Builder#addPerson(String)}. + * + * @deprecated the actual objects are now in {@link #EXTRA_PEOPLE_LIST} */ public static final String EXTRA_PEOPLE = "android.people"; /** + * {@link #extras} key: An arrayList of {@link Person} objects containing the people that + * this notification relates to. + */ + public static final String EXTRA_PEOPLE_LIST = "android.people.list"; + + /** * Allow certain system-generated notifications to appear before the device is provisioned. * Only available to notifications coming from the android package. * @hide @@ -1063,10 +1071,20 @@ public class Notification implements Parcelable * direct replies * {@link android.app.Notification.MessagingStyle} notification. This extra is a * {@link CharSequence} + * + * @deprecated use {@link #EXTRA_MESSAGING_PERSON} */ public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; /** + * {@link #extras} key: the person to be displayed for all messages sent by the user including + * direct replies + * {@link android.app.Notification.MessagingStyle} notification. This extra is a + * {@link Person} + */ + public static final String EXTRA_MESSAGING_PERSON = "android.messagingUser"; + + /** * {@link #extras} key: a {@link CharSequence} to be displayed as the title to a conversation * represented by a {@link android.app.Notification.MessagingStyle} */ @@ -2819,7 +2837,7 @@ public class Notification implements Parcelable private Bundle mUserExtras = new Bundle(); private Style mStyle; private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); - private ArrayList<String> mPersonList = new ArrayList<String>(); + private ArrayList<Person> mPersonList = new ArrayList<>(); private NotificationColorUtil mColorUtil; private boolean mIsLegacy; private boolean mIsLegacyInitialized; @@ -2910,8 +2928,9 @@ public class Notification implements Parcelable Collections.addAll(mActions, mN.actions); } - if (mN.extras.containsKey(EXTRA_PEOPLE)) { - Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE)); + if (mN.extras.containsKey(EXTRA_PEOPLE_LIST)) { + ArrayList<Person> people = mN.extras.getParcelableArrayList(EXTRA_PEOPLE_LIST); + mPersonList.addAll(people); } if (mN.getSmallIcon() == null && mN.icon != 0) { @@ -3621,13 +3640,41 @@ public class Notification implements Parcelable * URIs. The path part of these URIs must exist in the contacts database, in the * appropriate column, or the reference will be discarded as invalid. Telephone schema * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}. + * It is also possible to provide a URI with the schema {@code name:} in order to uniquely + * identify a person without an entry in the contacts database. * </P> * * @param uri A URI for the person. * @see Notification#EXTRA_PEOPLE + * @deprecated use {@link #addPerson(Person)} */ public Builder addPerson(String uri) { - mPersonList.add(uri); + addPerson(new Person().setUri(uri)); + return this; + } + + /** + * Add a person that is relevant to this notification. + * + * <P> + * Depending on user preferences, this annotation may allow the notification to pass + * through interruption filters, if this notification is of category {@link #CATEGORY_CALL} + * or {@link #CATEGORY_MESSAGE}. The addition of people may also cause this notification to + * appear more prominently in the user interface. + * </P> + * + * <P> + * A person should usually contain a uri in order to benefit from the ranking boost. + * However, even if no uri is provided, it's beneficial to provide other people in the + * notification, such that listeners and voice only devices can announce and handle them + * properly. + * </P> + * + * @param person the person to add. + * @see Notification#EXTRA_PEOPLE_LIST + */ + public Builder addPerson(Person person) { + mPersonList.add(person); return this; } @@ -3934,7 +3981,10 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.chronometer, View.GONE); contentView.setViewVisibility(R.id.header_text, View.GONE); contentView.setTextViewText(R.id.header_text, null); + contentView.setViewVisibility(R.id.header_text_secondary, View.GONE); + contentView.setTextViewText(R.id.header_text_secondary, null); contentView.setViewVisibility(R.id.header_text_divider, View.GONE); + contentView.setViewVisibility(R.id.header_text_secondary_divider, View.GONE); contentView.setViewVisibility(R.id.time_divider, View.GONE); contentView.setViewVisibility(R.id.time, View.GONE); contentView.setImageViewIcon(R.id.profile_badge, null); @@ -3965,7 +4015,7 @@ public class Notification implements Parcelable final Bundle ex = mN.extras; updateBackgroundColor(contentView); - bindNotificationHeader(contentView, p.ambient); + bindNotificationHeader(contentView, p.ambient, p.headerTextSecondary); bindLargeIcon(contentView, p.hideLargeIcon, p.alwaysShowReply); boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex); if (p.title != null) { @@ -4248,12 +4298,14 @@ public class Notification implements Parcelable return null; } - private void bindNotificationHeader(RemoteViews contentView, boolean ambient) { + private void bindNotificationHeader(RemoteViews contentView, boolean ambient, + CharSequence secondaryHeaderText) { bindSmallIcon(contentView, ambient); bindHeaderAppName(contentView, ambient); if (!ambient) { // Ambient view does not have these bindHeaderText(contentView); + bindHeaderTextSecondary(contentView, secondaryHeaderText); bindHeaderChronometerAndTime(contentView); bindProfileBadge(contentView); } @@ -4322,6 +4374,17 @@ public class Notification implements Parcelable } } + private void bindHeaderTextSecondary(RemoteViews contentView, CharSequence secondaryText) { + if (!TextUtils.isEmpty(secondaryText)) { + contentView.setTextViewText(R.id.header_text_secondary, processTextSpans( + processLegacyText(secondaryText))); + setTextViewColorSecondary(contentView, R.id.header_text_secondary); + contentView.setViewVisibility(R.id.header_text_secondary, View.VISIBLE); + contentView.setViewVisibility(R.id.header_text_secondary_divider, View.VISIBLE); + setTextViewColorSecondary(contentView, R.id.header_text_secondary_divider); + } + } + /** * @hide */ @@ -4555,7 +4618,7 @@ public class Notification implements Parcelable ambient ? R.layout.notification_template_ambient_header : R.layout.notification_template_header); resetNotificationHeader(header); - bindNotificationHeader(header, ambient); + bindNotificationHeader(header, ambient, null); if (colorized != null) { mN.extras.putBoolean(EXTRA_COLORIZED, colorized); } else { @@ -4968,8 +5031,7 @@ public class Notification implements Parcelable mActions.toArray(mN.actions); } if (!mPersonList.isEmpty()) { - mN.extras.putStringArray(EXTRA_PEOPLE, - mPersonList.toArray(new String[mPersonList.size()])); + mN.extras.putParcelableArrayList(EXTRA_PEOPLE_LIST, mPersonList); } if (mN.bigContentView != null || mN.contentView != null || mN.headsUpContentView != null) { @@ -5965,7 +6027,7 @@ public class Notification implements Parcelable */ public static final int MAXIMUM_RETAINED_MESSAGES = 25; - CharSequence mUserDisplayName; + @NonNull Person mUser; @Nullable CharSequence mConversationTitle; List<Message> mMessages = new ArrayList<>(); List<Message> mHistoricMessages = new ArrayList<>(); @@ -5979,16 +6041,40 @@ public class Notification implements Parcelable * user before the posting app reposts the notification with those messages after they've * been actually sent and in previous messages sent by the user added in * {@link #addMessage(Notification.MessagingStyle.Message)} + * + * @deprecated use {@code MessagingStyle(Person)} */ public MessagingStyle(@NonNull CharSequence userDisplayName) { - mUserDisplayName = userDisplayName; + this(new Person().setName(userDisplayName)); + } + + /** + * @param user Required - The person displayed for any messages that are sent by the + * user. Any messages added with {@link #addMessage(Notification.MessagingStyle.Message)} + * who don't have a Person associated with it will be displayed as if they were sent + * by this user. The user also needs to have a valid name associated with it. + */ + public MessagingStyle(@NonNull Person user) { + mUser = user; + if (user == null || user.getName() == null) { + throw new RuntimeException("user must be valid and have a name"); + } + } + + /** + * @return the user to be displayed for any replies sent by the user + */ + public Person getUser() { + return mUser; } /** * Returns the name to be displayed for any replies sent by the user + * + * @deprecated use {@link #getUser()} instead */ public CharSequence getUserDisplayName() { - return mUserDisplayName; + return mUser.getName(); } /** @@ -6031,8 +6117,28 @@ public class Notification implements Parcelable * @see Message#Message(CharSequence, long, CharSequence) * * @return this object for method chaining + * + * @deprecated use {@link #addMessage(CharSequence, long, Person)} */ public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) { + return addMessage(text, timestamp, + sender == null ? null : new Person().setName(sender)); + } + + /** + * Adds a message for display by this notification. Convenience call for a simple + * {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}. + * @param text A {@link CharSequence} to be displayed as the message content + * @param timestamp Time at which the message arrived + * @param sender The {@link Person} who sent the message. + * Should be <code>null</code> for messages by the current user, in which case + * the platform will insert the user set in {@code MessagingStyle(Person)}. + * + * @see Message#Message(CharSequence, long, CharSequence) + * + * @return this object for method chaining + */ + public MessagingStyle addMessage(CharSequence text, long timestamp, Person sender) { return addMessage(new Message(text, timestamp, sender)); } @@ -6131,8 +6237,10 @@ public class Notification implements Parcelable @Override public void addExtras(Bundle extras) { super.addExtras(extras); - if (mUserDisplayName != null) { - extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName); + if (mUser != null) { + // For legacy usages + extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUser.getName()); + extras.putParcelable(EXTRA_MESSAGING_PERSON, mUser); } if (mConversationTitle != null) { extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle); @@ -6152,14 +6260,15 @@ public class Notification implements Parcelable Message m = findLatestIncomingMessage(); CharSequence text = (m == null) ? null : m.mText; CharSequence sender = m == null ? null - : TextUtils.isEmpty(m.mSender) ? mUserDisplayName : m.mSender; + : m.mSender == null || TextUtils.isEmpty(m.mSender.getName()) + ? mUser.getName() : m.mSender.getName(); CharSequence title; if (!TextUtils.isEmpty(mConversationTitle)) { if (!TextUtils.isEmpty(sender)) { BidiFormatter bidi = BidiFormatter.getInstance(); title = mBuilder.mContext.getString( com.android.internal.R.string.notification_messaging_title_template, - bidi.unicodeWrap(mConversationTitle), bidi.unicodeWrap(m.mSender)); + bidi.unicodeWrap(mConversationTitle), bidi.unicodeWrap(sender)); } else { title = mConversationTitle; } @@ -6182,7 +6291,11 @@ public class Notification implements Parcelable protected void restoreFromExtras(Bundle extras) { super.restoreFromExtras(extras); - mUserDisplayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME); + mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON); + if (mUser == null) { + CharSequence displayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME); + mUser = new Person().setName(displayName); + } mConversationTitle = extras.getCharSequence(EXTRA_CONVERSATION_TITLE); Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES); mMessages = Message.getMessagesFromBundleArray(messages); @@ -6198,7 +6311,7 @@ public class Notification implements Parcelable public RemoteViews makeContentView(boolean increasedHeight) { mBuilder.mOriginalActions = mBuilder.mActions; mBuilder.mActions = new ArrayList<>(); - RemoteViews remoteViews = makeBigContentView(); + RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */); mBuilder.mActions = mBuilder.mOriginalActions; mBuilder.mOriginalActions = null; return remoteViews; @@ -6217,7 +6330,7 @@ public class Notification implements Parcelable for (int i = messages.size() - 1; i >= 0; i--) { Message m = messages.get(i); // Incoming messages have a non-empty sender. - if (!TextUtils.isEmpty(m.mSender)) { + if (m.mSender != null && !TextUtils.isEmpty(m.mSender.getName())) { return m; } } @@ -6233,23 +6346,31 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeBigContentView() { + return makeBigContentView(false /* showRightIcon */); + } + + @NonNull + private RemoteViews makeBigContentView(boolean showRightIcon) { CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; boolean isOneToOne = TextUtils.isEmpty(conversationTitle); - if (isOneToOne) { - // Let's add the conversationTitle in case we didn't have one before and all - // messages are from the same sender - conversationTitle = createConversationTitleFromMessages(); - } else if (hasOnlyWhiteSpaceSenders()) { + if (hasOnlyWhiteSpaceSenders()) { isOneToOne = true; } - boolean hasTitle = !TextUtils.isEmpty(conversationTitle); RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( mBuilder.getMessagingLayoutResource(), mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null) - .hideLargeIcon(isOneToOne).alwaysShowReply(true)); + .hideLargeIcon(!showRightIcon || isOneToOne) + .headerTextSecondary(conversationTitle) + .alwaysShowReply(showRightIcon)); addExtras(mBuilder.mN.extras); + // also update the end margin if there is an image + int endMargin = R.dimen.notification_content_margin_end; + if (mBuilder.mN.hasLargeIcon() && showRightIcon) { + endMargin = R.dimen.notification_content_plus_picture_margin_end; + } + contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin); contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor", mBuilder.resolveContrastColor()); contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon", @@ -6264,8 +6385,8 @@ public class Notification implements Parcelable private boolean hasOnlyWhiteSpaceSenders() { for (int i = 0; i < mMessages.size(); i++) { Message m = mMessages.get(i); - CharSequence sender = m.getSender(); - if (!isWhiteSpace(sender)) { + Person sender = m.getSenderPerson(); + if (sender != null && !isWhiteSpace(sender.getName())) { return false; } } @@ -6294,9 +6415,9 @@ public class Notification implements Parcelable ArraySet<CharSequence> names = new ArraySet<>(); for (int i = 0; i < mMessages.size(); i++) { Message m = mMessages.get(i); - CharSequence sender = m.getSender(); + Person sender = m.getSenderPerson(); if (sender != null) { - names.add(sender); + names.add(sender.getName()); } } SpannableStringBuilder title = new SpannableStringBuilder(); @@ -6316,7 +6437,7 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeHeadsUpContentView(boolean increasedHeight) { - RemoteViews remoteViews = makeBigContentView(); + RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */); remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); return remoteViews; } @@ -6331,13 +6452,15 @@ public class Notification implements Parcelable static final String KEY_TEXT = "text"; static final String KEY_TIMESTAMP = "time"; static final String KEY_SENDER = "sender"; + static final String KEY_SENDER_PERSON = "sender_person"; static final String KEY_DATA_MIME_TYPE = "type"; static final String KEY_DATA_URI= "uri"; static final String KEY_EXTRAS_BUNDLE = "extras"; private final CharSequence mText; private final long mTimestamp; - private final CharSequence mSender; + @Nullable + private final Person mSender; private Bundle mExtras = new Bundle(); private String mDataMimeType; @@ -6352,8 +6475,28 @@ public class Notification implements Parcelable * the platform will insert {@link MessagingStyle#getUserDisplayName()}. * Should be unique amongst all individuals in the conversation, and should be * consistent during re-posts of the notification. + * + * @deprecated use {@code Message(CharSequence, long, Person)} */ public Message(CharSequence text, long timestamp, CharSequence sender){ + this(text, timestamp, sender == null ? null : new Person().setName(sender)); + } + + /** + * Constructor + * @param text A {@link CharSequence} to be displayed as the message content + * @param timestamp Time at which the message arrived + * @param sender The {@link Person} who sent the message. + * Should be <code>null</code> for messages by the current user, in which case + * the platform will insert the user set in {@code MessagingStyle(Person)}. + * <p> + * The person provided should contain an Icon, set with {@link Person#setIcon(Icon)} + * and also have a name provided with {@link Person#setName(CharSequence)}. If multiple + * users have the same name, consider providing a key with {@link Person#setKey(String)} + * in order to differentiate between the different users. + * </p> + */ + public Message(CharSequence text, long timestamp, @Nullable Person sender){ mText = text; mTimestamp = timestamp; mSender = sender; @@ -6416,8 +6559,18 @@ public class Notification implements Parcelable /** * Get the text used to display the contact's name in the messaging experience + * + * @deprecated use {@link #getSenderPerson()} */ public CharSequence getSender() { + return mSender == null ? null : mSender.getName(); + } + + /** + * Get the sender associated with this message. + */ + @Nullable + public Person getSenderPerson() { return mSender; } @@ -6443,7 +6596,9 @@ public class Notification implements Parcelable } bundle.putLong(KEY_TIMESTAMP, mTimestamp); if (mSender != null) { - bundle.putCharSequence(KEY_SENDER, mSender); + // Legacy listeners need this + bundle.putCharSequence(KEY_SENDER, mSender.getName()); + bundle.putParcelable(KEY_SENDER_PERSON, mSender); } if (mDataMimeType != null) { bundle.putString(KEY_DATA_MIME_TYPE, mDataMimeType); @@ -6492,8 +6647,20 @@ public class Notification implements Parcelable if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) { return null; } else { + + Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON); + if (senderPerson == null) { + // Legacy apps that use compat don't actually provide the sender objects + // We need to fix the compat version to provide people / use + // the native api instead + CharSequence senderName = bundle.getCharSequence(KEY_SENDER); + if (senderName != null) { + senderPerson = new Person().setName(senderName); + } + } Message message = new Message(bundle.getCharSequence(KEY_TEXT), - bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER)); + bundle.getLong(KEY_TIMESTAMP), + senderPerson); if (bundle.containsKey(KEY_DATA_MIME_TYPE) && bundle.containsKey(KEY_DATA_URI)) { message.setData(bundle.getString(KEY_DATA_MIME_TYPE), @@ -7128,6 +7295,176 @@ public class Notification implements Parcelable } } + /** + * A Person associated with this Notification. + */ + public static final class Person implements Parcelable { + @Nullable private CharSequence mName; + @Nullable private Icon mIcon; + @Nullable private String mUri; + @Nullable private String mKey; + + protected Person(Parcel in) { + mName = in.readCharSequence(); + if (in.readInt() != 0) { + mIcon = Icon.CREATOR.createFromParcel(in); + } + mUri = in.readString(); + mKey = in.readString(); + } + + /** + * Create a new person. + */ + public Person() { + } + + /** + * Give this person a name. + * + * @param name the name of this person + */ + public Person setName(@Nullable CharSequence name) { + this.mName = name; + return this; + } + + /** + * Add an icon for this person. + * <br /> + * This is currently only used for {@link MessagingStyle} notifications and should not be + * provided otherwise, in order to save memory. The system will prefer this icon over any + * images that are resolved from the URI. + * + * @param icon the icon of the person + */ + public Person setIcon(@Nullable Icon icon) { + this.mIcon = icon; + return this; + } + + /** + * Set a URI associated with this person. + * + * <P> + * Depending on user preferences, adding a URI to a Person may allow the notification to + * pass through interruption filters, if this notification is of + * category {@link #CATEGORY_CALL} or {@link #CATEGORY_MESSAGE}. + * The addition of people may also cause this notification to appear more prominently in + * the user interface. + * </P> + * + * <P> + * The person should be specified by the {@code String} representation of a + * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}. + * </P> + * + * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema + * URIs. The path part of these URIs must exist in the contacts database, in the + * appropriate column, or the reference will be discarded as invalid. Telephone schema + * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}. + * </P> + * + * @param uri a URI for the person + */ + public Person setUri(@Nullable String uri) { + mUri = uri; + return this; + } + + /** + * Add a key to this person in order to uniquely identify it. + * This is especially useful if the name doesn't uniquely identify this person or if the + * display name is a short handle of the actual name. + * + * <P>If no key is provided, the name serves as as the key for the purpose of + * identification.</P> + * + * @param key the key that uniquely identifies this person + */ + public Person setKey(@Nullable String key) { + mKey = key; + return this; + } + + + /** + * @return the uri provided for this person or {@code null} if no Uri was provided + */ + @Nullable + public String getUri() { + return mUri; + } + + /** + * @return the name provided for this person or {@code null} if no name was provided + */ + @Nullable + public CharSequence getName() { + return mName; + } + + /** + * @return the icon provided for this person or {@code null} if no icon was provided + */ + @Nullable + public Icon getIcon() { + return mIcon; + } + + /** + * @return the key provided for this person or {@code null} if no key was provided + */ + @Nullable + public String getKey() { + return mKey; + } + + /** + * @return the URI associated with this person, or "name:mName" otherwise + * @hide + */ + public String resolveToLegacyUri() { + if (mUri != null) { + return mUri; + } + if (mName != null) { + return "name:" + mName; + } + return ""; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, @WriteFlags int flags) { + dest.writeCharSequence(mName); + if (mIcon != null) { + dest.writeInt(1); + mIcon.writeToParcel(dest, 0); + } else { + dest.writeInt(0); + } + dest.writeString(mUri); + dest.writeString(mKey); + } + + public static final Creator<Person> CREATOR = new Creator<Person>() { + @Override + public Person createFromParcel(Parcel in) { + return new Person(in); + } + + @Override + public Person[] newArray(int size) { + return new Person[size]; + } + }; + } + // When adding a new Style subclass here, don't forget to update // Builder.getNotificationStyleClass. @@ -8567,6 +8904,7 @@ public class Notification implements Parcelable boolean ambient = false; CharSequence title; CharSequence text; + CharSequence headerTextSecondary; boolean hideLargeIcon; public boolean alwaysShowReply; @@ -8575,6 +8913,7 @@ public class Notification implements Parcelable ambient = false; title = null; text = null; + headerTextSecondary = null; return this; } @@ -8593,6 +8932,11 @@ public class Notification implements Parcelable return this; } + final StandardTemplateParams headerTextSecondary(CharSequence text) { + this.headerTextSecondary = text; + return this; + } + final StandardTemplateParams alwaysShowReply(boolean alwaysShowReply) { this.alwaysShowReply = alwaysShowReply; return this; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2ec4906f082b..66d1bba0d855 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9802,6 +9802,14 @@ public final class Settings { public static final java.lang.String APP_STANDBY_ENABLED = "app_standby_enabled"; /** + * Feature flag to enable or disable the Forced App Standby feature. + * Type: int (0 for false, 1 for true) + * Default: 1 + * @hide + */ + public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled"; + + /** * Whether or not Network Watchlist feature is enabled. * Type: int (0 for false, 1 for true) * Default: 0 diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 18d4a1e63804..20cd90679195 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -890,6 +890,8 @@ public abstract class NotificationListenerService extends Service { createLegacyIconExtras(notification); // populate remote views for older clients. maybePopulateRemoteViews(notification); + // populate people for older clients. + maybePopulatePeople(notification); } catch (IllegalArgumentException e) { if (corruptNotifications == null) { corruptNotifications = new ArrayList<>(N); @@ -1178,6 +1180,25 @@ public abstract class NotificationListenerService extends Service { } } + /** + * Populates remote views for pre-P targeting apps. + */ + private void maybePopulatePeople(Notification notification) { + if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) { + ArrayList<Notification.Person> people = notification.extras.getParcelableArrayList( + Notification.EXTRA_PEOPLE_LIST); + if (people != null && people.isEmpty()) { + int size = people.size(); + String[] peopleArray = new String[size]; + for (int i = 0; i < size; i++) { + Notification.Person person = people.get(i); + peopleArray[i] = person.resolveToLegacyUri(); + } + notification.extras.putStringArray(Notification.EXTRA_PEOPLE, peopleArray); + } + } + } + /** @hide */ protected class NotificationListenerWrapper extends INotificationListener.Stub { @Override diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index 530937e720a7..ce8998fcb863 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -23,6 +23,9 @@ import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WIT import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_DSA_WITH_SHA256; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_ECDSA_WITH_SHA256; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice; @@ -35,7 +38,6 @@ import android.util.ArrayMap; import android.util.Pair; import java.io.ByteArrayInputStream; -import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; @@ -139,7 +141,7 @@ public class ApkSignatureSchemeV2Verifier { private static X509Certificate[][] verify(RandomAccessFile apk, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { SignatureInfo signatureInfo = findSignature(apk); - return verify(apk.getFD(), signatureInfo, verifyIntegrity); + return verify(apk, signatureInfo, verifyIntegrity); } /** @@ -162,9 +164,9 @@ public class ApkSignatureSchemeV2Verifier { * against the APK file. */ private static X509Certificate[][] verify( - FileDescriptor apkFileDescriptor, + RandomAccessFile apk, SignatureInfo signatureInfo, - boolean doVerifyIntegrity) throws SecurityException { + boolean doVerifyIntegrity) throws SecurityException, IOException { int signerCount = 0; Map<Integer, byte[]> contentDigests = new ArrayMap<>(); List<X509Certificate[]> signerCerts = new ArrayList<>(); @@ -202,13 +204,7 @@ public class ApkSignatureSchemeV2Verifier { } if (doVerifyIntegrity) { - ApkSigningBlockUtils.verifyIntegrity( - contentDigests, - apkFileDescriptor, - signatureInfo.apkSigningBlockOffset, - signatureInfo.centralDirOffset, - signatureInfo.eocdOffset, - signatureInfo.eocd); + ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } return signerCerts.toArray(new X509Certificate[signerCerts.size()][]); @@ -386,6 +382,7 @@ public class ApkSignatureSchemeV2Verifier { } return; } + private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) { switch (sigAlgorithm) { case SIGNATURE_RSA_PSS_WITH_SHA256: @@ -395,6 +392,9 @@ public class ApkSignatureSchemeV2Verifier { case SIGNATURE_ECDSA_WITH_SHA256: case SIGNATURE_ECDSA_WITH_SHA512: case SIGNATURE_DSA_WITH_SHA256: + case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256: + case SIGNATURE_VERITY_ECDSA_WITH_SHA256: + case SIGNATURE_VERITY_DSA_WITH_SHA256: return true; default: return false; diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index e43dee356064..c9e67fe1c9ef 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -23,6 +23,9 @@ import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WIT import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_RSA_PSS_WITH_SHA512; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_DSA_WITH_SHA256; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_ECDSA_WITH_SHA256; +import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getLengthPrefixedSlice; @@ -36,7 +39,6 @@ import android.util.ArrayMap; import android.util.Pair; import java.io.ByteArrayInputStream; -import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; @@ -136,7 +138,7 @@ public class ApkSignatureSchemeV3Verifier { private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { SignatureInfo signatureInfo = findSignature(apk); - return verify(apk.getFD(), signatureInfo, verifyIntegrity); + return verify(apk, signatureInfo, verifyIntegrity); } /** @@ -159,7 +161,7 @@ public class ApkSignatureSchemeV3Verifier { * against the APK file. */ private static VerifiedSigner verify( - FileDescriptor apkFileDescriptor, + RandomAccessFile apk, SignatureInfo signatureInfo, boolean doVerifyIntegrity) throws SecurityException { int signerCount = 0; @@ -206,13 +208,7 @@ public class ApkSignatureSchemeV3Verifier { } if (doVerifyIntegrity) { - ApkSigningBlockUtils.verifyIntegrity( - contentDigests, - apkFileDescriptor, - signatureInfo.apkSigningBlockOffset, - signatureInfo.centralDirOffset, - signatureInfo.eocdOffset, - signatureInfo.eocd); + ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } return result; @@ -512,6 +508,9 @@ public class ApkSignatureSchemeV3Verifier { case SIGNATURE_ECDSA_WITH_SHA256: case SIGNATURE_ECDSA_WITH_SHA512: case SIGNATURE_DSA_WITH_SHA256: + case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256: + case SIGNATURE_VERITY_ECDSA_WITH_SHA256: + case SIGNATURE_VERITY_DSA_WITH_SHA256: return true; default: return false; diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java index 9279510ae58f..9d53847f8110 100644 --- a/core/java/android/util/apk/ApkSigningBlockUtils.java +++ b/core/java/android/util/apk/ApkSigningBlockUtils.java @@ -16,6 +16,7 @@ package android.util.apk; +import android.util.ArrayMap; import android.util.Pair; import java.io.FileDescriptor; @@ -30,6 +31,7 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.MGF1ParameterSpec; import java.security.spec.PSSParameterSpec; +import java.util.Arrays; import java.util.Map; /** @@ -84,16 +86,41 @@ final class ApkSigningBlockUtils { static void verifyIntegrity( Map<Integer, byte[]> expectedDigests, - FileDescriptor apkFileDescriptor, - long apkSigningBlockOffset, - long centralDirOffset, - long eocdOffset, - ByteBuffer eocdBuf) throws SecurityException { - + RandomAccessFile apk, + SignatureInfo signatureInfo) throws SecurityException { if (expectedDigests.isEmpty()) { throw new SecurityException("No digests provided"); } + Map<Integer, byte[]> expected1MbChunkDigests = new ArrayMap<>(); + if (expectedDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA256)) { + expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA256, + expectedDigests.get(CONTENT_DIGEST_CHUNKED_SHA256)); + } + if (expectedDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA512)) { + expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA512, + expectedDigests.get(CONTENT_DIGEST_CHUNKED_SHA512)); + } + + if (expectedDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { + verifyIntegrityForVerityBasedAlgorithm( + expectedDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256), apk, signatureInfo); + } else if (!expected1MbChunkDigests.isEmpty()) { + try { + verifyIntegrityFor1MbChunkBasedAlgorithm(expected1MbChunkDigests, apk.getFD(), + signatureInfo); + } catch (IOException e) { + throw new SecurityException("Cannot get FD", e); + } + } else { + throw new SecurityException("No known digest exists for integrity check"); + } + } + + private static void verifyIntegrityFor1MbChunkBasedAlgorithm( + Map<Integer, byte[]> expectedDigests, + FileDescriptor apkFileDescriptor, + SignatureInfo signatureInfo) throws SecurityException { // We need to verify the integrity of the following three sections of the file: // 1. Everything up to the start of the APK Signing Block. // 2. ZIP Central Directory. @@ -105,16 +132,18 @@ final class ApkSigningBlockUtils { // APK are already there in the OS's page cache and thus mmap does not use additional // physical memory. DataSource beforeApkSigningBlock = - new MemoryMappedFileDataSource(apkFileDescriptor, 0, apkSigningBlockOffset); + new MemoryMappedFileDataSource(apkFileDescriptor, 0, + signatureInfo.apkSigningBlockOffset); DataSource centralDir = new MemoryMappedFileDataSource( - apkFileDescriptor, centralDirOffset, eocdOffset - centralDirOffset); + apkFileDescriptor, signatureInfo.centralDirOffset, + signatureInfo.eocdOffset - signatureInfo.centralDirOffset); // For the purposes of integrity verification, ZIP End of Central Directory's field Start of // Central Directory must be considered to point to the offset of the APK Signing Block. - eocdBuf = eocdBuf.duplicate(); + ByteBuffer eocdBuf = signatureInfo.eocd.duplicate(); eocdBuf.order(ByteOrder.LITTLE_ENDIAN); - ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, apkSigningBlockOffset); + ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, signatureInfo.apkSigningBlockOffset); DataSource eocd = new ByteBufferDataSource(eocdBuf); int[] digestAlgorithms = new int[expectedDigests.size()]; @@ -126,7 +155,7 @@ final class ApkSigningBlockUtils { byte[][] actualDigests; try { actualDigests = - computeContentDigests( + computeContentDigestsPer1MbChunk( digestAlgorithms, new DataSource[] {beforeApkSigningBlock, centralDir, eocd}); } catch (DigestException e) { @@ -144,7 +173,7 @@ final class ApkSigningBlockUtils { } } - private static byte[][] computeContentDigests( + private static byte[][] computeContentDigestsPer1MbChunk( int[] digestAlgorithms, DataSource[] contents) throws DigestException { // For each digest algorithm the result is computed as follows: @@ -256,6 +285,26 @@ final class ApkSigningBlockUtils { return result; } + private static void verifyIntegrityForVerityBasedAlgorithm( + byte[] expectedRootHash, + RandomAccessFile apk, + SignatureInfo signatureInfo) throws SecurityException { + try { + ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk, + signatureInfo, new ByteBufferFactory() { + @Override + public ByteBuffer create(int capacity) { + return ByteBuffer.allocate(capacity); + } + }); + if (!Arrays.equals(expectedRootHash, verity.rootHash)) { + throw new SecurityException("APK verity digest of contents did not verify"); + } + } catch (DigestException | IOException | NoSuchAlgorithmException e) { + throw new SecurityException("Error during verification", e); + } + } + /** * Returns the ZIP End of Central Directory (EoCD) and its offset in the file. * @@ -304,9 +353,13 @@ final class ApkSigningBlockUtils { static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201; static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202; static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301; + static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0401; + static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0403; + static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0405; static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1; static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2; + static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3; static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) { int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1); @@ -321,6 +374,7 @@ final class ApkSigningBlockUtils { case CONTENT_DIGEST_CHUNKED_SHA256: return 0; case CONTENT_DIGEST_CHUNKED_SHA512: + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: return -1; default: throw new IllegalArgumentException( @@ -329,6 +383,7 @@ final class ApkSigningBlockUtils { case CONTENT_DIGEST_CHUNKED_SHA512: switch (digestAlgorithm2) { case CONTENT_DIGEST_CHUNKED_SHA256: + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: return 1; case CONTENT_DIGEST_CHUNKED_SHA512: return 0; @@ -336,6 +391,18 @@ final class ApkSigningBlockUtils { throw new IllegalArgumentException( "Unknown digestAlgorithm2: " + digestAlgorithm2); } + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: + switch (digestAlgorithm2) { + case CONTENT_DIGEST_CHUNKED_SHA512: + return -1; + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: + return 0; + case CONTENT_DIGEST_CHUNKED_SHA256: + return 1; + default: + throw new IllegalArgumentException( + "Unknown digestAlgorithm2: " + digestAlgorithm2); + } default: throw new IllegalArgumentException("Unknown digestAlgorithm1: " + digestAlgorithm1); } @@ -352,6 +419,10 @@ final class ApkSigningBlockUtils { case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512: case SIGNATURE_ECDSA_WITH_SHA512: return CONTENT_DIGEST_CHUNKED_SHA512; + case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256: + case SIGNATURE_VERITY_ECDSA_WITH_SHA256: + case SIGNATURE_VERITY_DSA_WITH_SHA256: + return CONTENT_DIGEST_VERITY_CHUNKED_SHA256; default: throw new IllegalArgumentException( "Unknown signature algorithm: 0x" @@ -362,6 +433,7 @@ final class ApkSigningBlockUtils { static String getContentDigestAlgorithmJcaDigestAlgorithm(int digestAlgorithm) { switch (digestAlgorithm) { case CONTENT_DIGEST_CHUNKED_SHA256: + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: return "SHA-256"; case CONTENT_DIGEST_CHUNKED_SHA512: return "SHA-512"; @@ -374,6 +446,7 @@ final class ApkSigningBlockUtils { private static int getContentDigestAlgorithmOutputSizeBytes(int digestAlgorithm) { switch (digestAlgorithm) { case CONTENT_DIGEST_CHUNKED_SHA256: + case CONTENT_DIGEST_VERITY_CHUNKED_SHA256: return 256 / 8; case CONTENT_DIGEST_CHUNKED_SHA512: return 512 / 8; @@ -389,11 +462,14 @@ final class ApkSigningBlockUtils { case SIGNATURE_RSA_PSS_WITH_SHA512: case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256: case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512: + case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256: return "RSA"; case SIGNATURE_ECDSA_WITH_SHA256: case SIGNATURE_ECDSA_WITH_SHA512: + case SIGNATURE_VERITY_ECDSA_WITH_SHA256: return "EC"; case SIGNATURE_DSA_WITH_SHA256: + case SIGNATURE_VERITY_DSA_WITH_SHA256: return "DSA"; default: throw new IllegalArgumentException( @@ -416,14 +492,17 @@ final class ApkSigningBlockUtils { new PSSParameterSpec( "SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1)); case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256: + case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256: return Pair.create("SHA256withRSA", null); case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512: return Pair.create("SHA512withRSA", null); case SIGNATURE_ECDSA_WITH_SHA256: + case SIGNATURE_VERITY_ECDSA_WITH_SHA256: return Pair.create("SHA256withECDSA", null); case SIGNATURE_ECDSA_WITH_SHA512: return Pair.create("SHA512withECDSA", null); case SIGNATURE_DSA_WITH_SHA256: + case SIGNATURE_VERITY_DSA_WITH_SHA256: return Pair.create("SHA256withDSA", null); default: throw new IllegalArgumentException( diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index ab0b3eec8753..fbba8abff304 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -47,6 +47,7 @@ public class NotificationHeaderView extends ViewGroup { private final int mGravity; private View mAppName; private View mHeaderText; + private View mSecondaryHeaderText; private OnClickListener mExpandClickListener; private HeaderTouchListener mTouchListener = new HeaderTouchListener(); private ImageView mExpandButton; @@ -58,7 +59,6 @@ public class NotificationHeaderView extends ViewGroup { private boolean mShowExpandButtonAtEnd; private boolean mShowWorkBadgeAtEnd; private Drawable mBackground; - private int mHeaderBackgroundHeight; private boolean mEntireHeaderClickable; private boolean mExpandOnlyOnButton; private boolean mAcceptAllTouches; @@ -68,7 +68,7 @@ public class NotificationHeaderView extends ViewGroup { @Override public void getOutline(View view, Outline outline) { if (mBackground != null) { - outline.setRect(0, 0, getWidth(), mHeaderBackgroundHeight); + outline.setRect(0, 0, getWidth(), getHeight()); outline.setAlpha(1f); } } @@ -91,8 +91,6 @@ public class NotificationHeaderView extends ViewGroup { Resources res = getResources(); mChildMinWidth = res.getDimensionPixelSize(R.dimen.notification_header_shrink_min_width); mContentEndMargin = res.getDimensionPixelSize(R.dimen.notification_content_margin_end); - mHeaderBackgroundHeight = res.getDimensionPixelSize( - R.dimen.notification_header_background_height); mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand); int[] attrIds = { android.R.attr.gravity }; @@ -106,6 +104,7 @@ public class NotificationHeaderView extends ViewGroup { super.onFinishInflate(); mAppName = findViewById(com.android.internal.R.id.app_name_text); mHeaderText = findViewById(com.android.internal.R.id.header_text); + mSecondaryHeaderText = findViewById(com.android.internal.R.id.header_text_secondary); mExpandButton = findViewById(com.android.internal.R.id.expand_button); mIcon = findViewById(com.android.internal.R.id.icon); mProfileBadge = findViewById(com.android.internal.R.id.profile_badge); @@ -137,26 +136,33 @@ public class NotificationHeaderView extends ViewGroup { if (totalWidth > givenWidth) { int overFlow = totalWidth - givenWidth; // We are overflowing, lets shrink the app name first - final int appWidth = mAppName.getMeasuredWidth(); - if (overFlow > 0 && mAppName.getVisibility() != GONE && appWidth > mChildMinWidth) { - int newSize = appWidth - Math.min(appWidth - mChildMinWidth, overFlow); - int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); - mAppName.measure(childWidthSpec, wrapContentHeightSpec); - overFlow -= appWidth - newSize; - } - // still overflowing, finaly we shrink the header text - if (overFlow > 0 && mHeaderText.getVisibility() != GONE) { - // we're still too big - final int textWidth = mHeaderText.getMeasuredWidth(); - int newSize = Math.max(0, textWidth - overFlow); - int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); - mHeaderText.measure(childWidthSpec, wrapContentHeightSpec); - } + overFlow = shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mAppName, + mChildMinWidth); + + // still overflowing, we shrink the header text + overFlow = shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mHeaderText, 0); + + // still overflowing, finally we shrink the secondary header text + shrinkViewForOverflow(wrapContentHeightSpec, overFlow, mSecondaryHeaderText, + 0); } mTotalWidth = Math.min(totalWidth, givenWidth); setMeasuredDimension(givenWidth, givenHeight); } + private int shrinkViewForOverflow(int heightSpec, int overFlow, View targetView, + int minimumWidth) { + final int oldWidth = targetView.getMeasuredWidth(); + if (overFlow > 0 && targetView.getVisibility() != GONE && oldWidth > minimumWidth) { + // we're still too big + int newSize = Math.max(minimumWidth, oldWidth - overFlow); + int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); + targetView.measure(childWidthSpec, heightSpec); + overFlow -= oldWidth - newSize; + } + return overFlow; + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = getPaddingStart(); @@ -228,7 +234,7 @@ public class NotificationHeaderView extends ViewGroup { @Override protected void onDraw(Canvas canvas) { if (mBackground != null) { - mBackground.setBounds(0, 0, getWidth(), mHeaderBackgroundHeight); + mBackground.setBounds(0, 0, getWidth(), getHeight()); mBackground.draw(canvas); } } diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java index 792f9212d93e..20f05e61687f 100644 --- a/core/java/com/android/internal/widget/MessagingGroup.java +++ b/core/java/com/android/internal/widget/MessagingGroup.java @@ -20,17 +20,12 @@ import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; +import android.app.Notification; import android.content.Context; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Pools; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -41,7 +36,6 @@ import android.widget.LinearLayout; import android.widget.RemoteViews; import com.android.internal.R; -import com.android.internal.util.NotificationColorUtil; import java.util.ArrayList; import java.util.List; @@ -60,12 +54,12 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou private int mLayoutColor; private CharSequence mAvatarName = ""; private Icon mAvatarIcon; - private ColorFilter mMessageBackgroundFilter; private int mTextColor; private List<MessagingMessage> mMessages; private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>(); private boolean mFirstLayout; private boolean mIsHidingAnimated; + private boolean mNeedsGeneratedAvatar; public MessagingGroup(@NonNull Context context) { super(context); @@ -94,27 +88,19 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mAvatarView = findViewById(R.id.message_icon); } - public void setSender(CharSequence sender) { - if (sender == null) { - mAvatarView.setVisibility(GONE); - mSenderName.setVisibility(GONE); - setGravity(Gravity.END); - mMessageBackgroundFilter = new PorterDuffColorFilter(mLayoutColor, - PorterDuff.Mode.SRC_ATOP); - mTextColor = NotificationColorUtil.isColorLight(mLayoutColor) ? getNormalTextColor() - : Color.WHITE; - } else { - mSenderName.setText(sender); - mAvatarView.setVisibility(VISIBLE); - mSenderName.setVisibility(VISIBLE); - setGravity(Gravity.START); - mMessageBackgroundFilter = null; - mTextColor = getNormalTextColor(); + public void setSender(Notification.Person sender) { + mSenderName.setText(sender.getName()); + mNeedsGeneratedAvatar = sender.getIcon() == null; + if (!mNeedsGeneratedAvatar) { + setAvatar(sender.getIcon()); } + mAvatarView.setVisibility(VISIBLE); + mSenderName.setVisibility(VISIBLE); + mTextColor = getNormalTextColor(); } private int getNormalTextColor() { - return mContext.getColor(R.color.notification_primary_text_color_light); + return mContext.getColor(R.color.notification_secondary_text_color_light); } public void setAvatar(Icon icon) { @@ -207,10 +193,6 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou return mSenderName.getText(); } - public void setSenderVisible(boolean visible) { - mSenderName.setVisibility(visible ? VISIBLE : GONE); - } - public static void dropCache() { sInstancePool = new Pools.SynchronizedPool<>(10); } @@ -317,12 +299,6 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mMessageContainer.removeView(message); mMessageContainer.addView(message, messageIndex); } - // Let's make sure the message color is correct - Drawable targetDrawable = message.getBackground(); - - if (targetDrawable != null) { - targetDrawable.mutate().setColorFilter(mMessageBackgroundFilter); - } message.setTextColor(mTextColor); } mMessages = group; @@ -390,4 +366,8 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou public MessagingLinearLayout getMessageContainer() { return mMessageContainer; } + + public boolean needsGeneratedAvatar() { + return mNeedsGeneratedAvatar; + } } diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index 2acdc015f8ef..834c93a7a98f 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -69,7 +69,6 @@ public class MessagingLayout extends FrameLayout { private List<MessagingMessage> mMessages = new ArrayList<>(); private List<MessagingMessage> mHistoricMessages = new ArrayList<>(); private MessagingLinearLayout mMessagingLinearLayout; - private View mContractedMessage; private boolean mShowHistoricMessages; private ArrayList<MessagingGroup> mGroups = new ArrayList<>(); private TextView mTitleView; @@ -81,6 +80,7 @@ public class MessagingLayout extends FrameLayout { private Icon mLargeIcon; private boolean mIsOneToOne; private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>(); + private Notification.Person mUser; public MessagingLayout(@NonNull Context context) { super(context); @@ -129,6 +129,7 @@ public class MessagingLayout extends FrameLayout { Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES); List<Notification.MessagingStyle.Message> newHistoricMessages = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages); + setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON)); mConversationTitle = null; TextView headerText = findViewById(R.id.header_text); if (headerText != null) { @@ -152,7 +153,6 @@ public class MessagingLayout extends FrameLayout { mMessages = messages; mHistoricMessages = historicMessages; - updateContractedMessage(); updateHistoricMessageVisibility(); updateTitleAndNamesDisplay(); } @@ -163,12 +163,10 @@ public class MessagingLayout extends FrameLayout { for (int i = 0; i < mGroups.size(); i++) { MessagingGroup group = mGroups.get(i); CharSequence senderName = group.getSenderName(); - if (TextUtils.isEmpty(senderName)) { + if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } - boolean visible = !mIsOneToOne; - group.setSenderVisible(visible); - if ((visible || mLargeIcon == null) && !uniqueNames.containsKey(senderName)) { + if (!uniqueNames.containsKey(senderName)) { char c = senderName.charAt(0); if (uniqueCharacters.containsKey(c)) { // this character was already used, lets make it more unique. We first need to @@ -192,7 +190,8 @@ public class MessagingLayout extends FrameLayout { // Let's now set the avatars MessagingGroup group = mGroups.get(i); CharSequence senderName = group.getSenderName(); - if (TextUtils.isEmpty(senderName) || (mIsOneToOne && mLargeIcon != null)) { + if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName) + || (mIsOneToOne && mLargeIcon != null)) { continue; } String symbol = uniqueNames.get(senderName); @@ -207,7 +206,7 @@ public class MessagingLayout extends FrameLayout { // Let's now set the avatars MessagingGroup group = mGroups.get(i); CharSequence senderName = group.getSenderName(); - if (TextUtils.isEmpty(senderName)) { + if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) { continue; } if (mIsOneToOne && mLargeIcon != null) { @@ -234,7 +233,7 @@ public class MessagingLayout extends FrameLayout { canvas.drawCircle(radius, radius, radius, mPaint); boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f; mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE); - mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.75f : mAvatarSize * 0.4f); + mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f); int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ; canvas.drawText(symbol, radius, yPos, mTextPaint); return Icon.createWithBitmap(bitmap); @@ -270,11 +269,15 @@ public class MessagingLayout extends FrameLayout { mIsOneToOne = oneToOne; } + public void setUser(Notification.Person user) { + mUser = user; + } + private void addMessagesToGroups(List<MessagingMessage> historicMessages, List<MessagingMessage> messages) { // Let's first find our groups! List<List<MessagingMessage>> groups = new ArrayList<>(); - List<CharSequence> senders = new ArrayList<>(); + List<Notification.Person> senders = new ArrayList<>(); // Lets first find the groups findGroups(historicMessages, messages, groups, senders); @@ -283,7 +286,8 @@ public class MessagingLayout extends FrameLayout { createGroupViews(groups, senders); } - private void createGroupViews(List<List<MessagingMessage>> groups, List<CharSequence> senders) { + private void createGroupViews(List<List<MessagingMessage>> groups, + List<Notification.Person> senders) { mGroups.clear(); for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) { List<MessagingMessage> group = groups.get(groupIndex); @@ -314,8 +318,8 @@ public class MessagingLayout extends FrameLayout { private void findGroups(List<MessagingMessage> historicMessages, List<MessagingMessage> messages, List<List<MessagingMessage>> groups, - List<CharSequence> senders) { - CharSequence currentSender = null; + List<Notification.Person> senders) { + CharSequence currentSenderKey = null; List<MessagingMessage> currentGroup = null; int histSize = historicMessages.size(); for (int i = 0; i < histSize + messages.size(); i++) { @@ -326,35 +330,23 @@ public class MessagingLayout extends FrameLayout { message = messages.get(i - histSize); } boolean isNewGroup = currentGroup == null; - CharSequence sender = message.getMessage().getSender(); - isNewGroup |= !TextUtils.equals(sender, currentSender); + Notification.Person sender = message.getMessage().getSenderPerson(); + CharSequence key = sender == null ? null + : sender.getKey() == null ? sender.getName() : sender.getKey(); + isNewGroup |= !TextUtils.equals(key, currentSenderKey); if (isNewGroup) { currentGroup = new ArrayList<>(); groups.add(currentGroup); + if (sender == null) { + sender = mUser; + } senders.add(sender); - currentSender = sender; + currentSenderKey = key; } currentGroup.add(message); } } - private void updateContractedMessage() { - for (int i = mMessages.size() - 1; i >= 0; i--) { - MessagingMessage m = mMessages.get(i); - // Incoming messages have a non-empty sender. - if (!TextUtils.isEmpty(m.getMessage().getSender())) { - mContractedMessage = m; - return; - } - } - if (!mMessages.isEmpty()) { - // No incoming messages, fall back to outgoing message - mContractedMessage = mMessages.get(mMessages.size() - 1); - return; - } - mContractedMessage = null; - } - /** * Creates new messages, reusing existing ones if they are available. * @@ -430,10 +422,6 @@ public class MessagingLayout extends FrameLayout { } } - public View getContractedMessage() { - return mContractedMessage; - } - public MessagingLinearLayout getMessagingLinearLayout() { return mMessagingLinearLayout; } diff --git a/core/res/res/drawable/messaging_message_background.xml b/core/res/res/drawable/messaging_message_background.xml deleted file mode 100644 index 8a2096a62473..000000000000 --- a/core/res/res/drawable/messaging_message_background.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?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 - --> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle" - android:tint="#14000000"> - <corners android:radius="4dp" /> - <padding android:bottom="6dp" - android:left="8dp" - android:right="8dp" - android:top="6dp" /> -</shape> diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index 3a28f4d76f7c..20bdf3fe8fa3 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -41,6 +41,24 @@ android:singleLine="true" /> <TextView + android:id="@+id/header_text_secondary_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?attr/notificationHeaderTextAppearance" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:visibility="gone"/> + <TextView + android:id="@+id/header_text_secondary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?attr/notificationHeaderTextAppearance" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:visibility="gone" + android:singleLine="true"/> + <TextView android:id="@+id/header_text_divider" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml index f72230be0833..a72ad538a85c 100644 --- a/core/res/res/layout/notification_template_material_messaging.xml +++ b/core/res/res/layout/notification_template_material_messaging.xml @@ -21,10 +21,7 @@ android:layout_height="wrap_content" android:tag="messaging" > - <include layout="@layout/notification_template_header" - android:layout_width="wrap_content" - android:layout_height="@dimen/notification_header_height" - android:layout_marginEnd="56dp"/> + <include layout="@layout/notification_template_header"/> <LinearLayout android:id="@+id/notification_action_list_margin_target" android:layout_width="match_parent" @@ -39,28 +36,19 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - android:paddingStart="@dimen/notification_content_margin_start" - android:paddingEnd="@dimen/notification_content_margin_end" + android:layout_marginStart="@dimen/notification_content_margin_start" + android:layout_marginEnd="@dimen/notification_content_margin_end" android:minHeight="@dimen/notification_min_content_height" android:layout_marginBottom="@dimen/notification_content_margin_bottom" android:orientation="vertical" > - <include layout="@layout/notification_template_part_line1" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - <com.android.internal.widget.MessagingLinearLayout android:id="@+id/notification_messaging" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" android:spacing="@dimen/notification_messaging_spacing" /> </LinearLayout> </LinearLayout> <include layout="@layout/notification_material_action_list" /> - <include layout="@layout/notification_template_right_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="18dp" - android:layout_gravity="top|end"/> + <include layout="@layout/notification_template_right_icon"/> </com.android.internal.widget.MessagingLayout> diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml index 8973ceb5c3a1..4ac308a60d93 100644 --- a/core/res/res/layout/notification_template_messaging_group.xml +++ b/core/res/res/layout/notification_template_messaging_group.xml @@ -24,7 +24,7 @@ android:id="@+id/message_icon" android:layout_width="@dimen/messaging_avatar_size" android:layout_height="@dimen/messaging_avatar_size" - android:layout_marginEnd="8dp" + android:layout_marginEnd="12dp" android:scaleType="centerCrop" android:importantForAccessibility="no" /> <com.android.internal.widget.RemeasuringLinearLayout @@ -32,19 +32,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> + <com.android.internal.widget.ImageFloatingTextView + android:id="@+id/message_name" + style="@style/Widget.Material.Notification.MessagingName" + android:layout_width="wrap_content" + /> <com.android.internal.widget.MessagingLinearLayout android:id="@+id/group_message_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spacing="2dp" android:layout_weight="1"/> - <com.android.internal.widget.ImageFloatingTextView - android:id="@+id/message_name" - style="@style/Widget.Material.Notification.MessagingName" - android:layout_width="wrap_content" - android:paddingStart="8dp" - android:paddingEnd="8dp" - android:paddingTop="2dp" - /> </com.android.internal.widget.RemeasuringLinearLayout> </com.android.internal.widget.MessagingGroup> diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml index 8fb28877a81f..0b97e45b8eed 100644 --- a/core/res/res/layout/notification_template_right_icon.xml +++ b/core/res/res/layout/notification_template_right_icon.xml @@ -19,7 +19,7 @@ android:id="@+id/right_icon_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="36dp" + android:layout_marginTop="@dimen/notification_content_margin_top" android:layout_gravity="top|end"> <ImageView android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" @@ -32,8 +32,8 @@ android:layout_width="16dp" android:layout_height="16dp" android:layout_gravity="top|end" - android:layout_marginTop="28dp" - android:layout_marginEnd="12dp" + android:layout_marginTop="27dp" + android:layout_marginEnd="16dp" android:background="@drawable/notification_reply_background" android:src="@drawable/ic_reply_notification" android:scaleType="center" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index e33cfc1fd347..1bb341783f77 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kon nie die kortpad teruglaai nie omdat die program nie rugsteun en teruglaai steun nie"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kon nie teruglaai nie omdat programondertekening nie ooreenstem nie"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kon nie kortpad teruglaai nie"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index e9922666db23..0a996cabdf2a 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"መተግበሪያ ምትኬን እና ወደ ነበረበት መመለስን ሳለማይደግፍ አቋራጭ ወደ ነበረበት ሊመለስ አልቻለም"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"በመተግበሪያ ፊርማ አለመዛመድ አቋራጭን ወደነበረበት መመለስ አልተቻለም"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"አቋራጭን ወደ ነበረበት መመለስ አልተቻለም"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 2002084ff572..e929bf8efa72 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -51,7 +51,7 @@ <string name="needPuk2" msgid="4526033371987193070">"اكتب PUK2 لإلغاء تأمين شريحة SIM."</string> <string name="enablePin" msgid="209412020907207950">"محاولة غير ناجحة، مكّن قفل SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582"> - <item quantity="zero">لم يتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item> + <item quantity="zero">لم يتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item> <item quantity="two">يتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدهما قفل شريحة SIM.</item> <item quantity="few">يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات يتم بعدها قفل شريحة SIM.</item> <item quantity="many">يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة يتم بعدها قفل شريحة SIM.</item> @@ -448,9 +448,9 @@ <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"يتيح للتطبيق تغيير المنطقة الزمنية للتلفزيون."</string> <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"للسماح للتطبيق بتغيير المنطقة الزمنية للهاتف."</string> <string name="permlab_getAccounts" msgid="1086795467760122114">"البحث عن حسابات على الجهاز"</string> - <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الجهاز اللوحي. وقد يتضمن ذلك أية حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string> - <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"يتيح للتطبيق الحصول على قائمة بالحسابات المعروفة في التلفزيون. وقد يتضمن هذا أية حسابات أنشأتها التطبيقات التي ثبتها."</string> - <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الهاتف. وقد يتضمن ذلك أية حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string> + <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الجهاز اللوحي. وقد يتضمن ذلك أي حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string> + <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"يتيح للتطبيق الحصول على قائمة بالحسابات المعروفة في التلفزيون. وقد يتضمن هذا أي حسابات أنشأتها التطبيقات التي ثبتها."</string> + <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"للسماح للتطبيق بالحصول على قائمة بالحسابات التي يعرفها الهاتف. وقد يتضمن ذلك أي حسابات تم إنشاؤها بواسطة التطبيقات التي ثبتها."</string> <string name="permlab_accessNetworkState" msgid="4951027964348974773">"عرض اتصالات الشبكة"</string> <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"للسماح للتطبيق بعرض معلومات حول اتصالات الشبكة كعرض معلومات عن الشبكات المتوفرة والشبكات المتصلة."</string> <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"حق الوصول الكامل إلى الشبكة"</string> @@ -472,7 +472,7 @@ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"يتيح للتطبيق تهيئة تلفزيون بلوتوث المحلي، واكتشاف الأجهزة البعيدة وإقرانها."</string> <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"للسماح للتطبيق بتهيئة هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران بها."</string> <string name="permlab_accessWimaxState" msgid="4195907010610205703">"الاتصال بـشبكة WiMAX وقطع الاتصال بها"</string> - <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"للسماح للتطبيق بتحديد ما إذا تم تمكين WiMAX وتحديد معلومات حول أية شبكات WiMAX متصلة."</string> + <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"للسماح للتطبيق بتحديد ما إذا تم تمكين WiMAX وتحديد معلومات حول أي شبكات WiMAX متصلة."</string> <string name="permlab_changeWimaxState" msgid="340465839241528618">"تغيير حالة WiMAX"</string> <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"للسماح للتطبيق بتوصيل الجهاز اللوحي بشبكات WiMAX وقطع اتصاله بها."</string> <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"يتيح للتطبيق توصيل التلفزيون أو إلغاء توصيله بشبكات WiMAX."</string> @@ -817,7 +817,7 @@ <string name="granularity_label_line" msgid="5764267235026120888">"سطر"</string> <string name="factorytest_failed" msgid="5410270329114212041">"تعذّر اختبار المصنع"</string> <string name="factorytest_not_system" msgid="4435201656767276723">"إجراء FACTORY_TEST غير متاح سوى للحزم المثبتة في /system/app."</string> - <string name="factorytest_no_action" msgid="872991874799998561">"لم يتم العثور على أية حزمة توفر إجراء FACTORY_TEST."</string> + <string name="factorytest_no_action" msgid="872991874799998561">"لم يتم العثور على أي حزمة توفر إجراء FACTORY_TEST."</string> <string name="factorytest_reboot" msgid="6320168203050791643">"إعادة تشغيل"</string> <string name="js_dialog_title" msgid="1987483977834603872">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string> <string name="js_dialog_title_default" msgid="6961903213729667573">"جافا سكريبت"</string> @@ -1186,7 +1186,7 @@ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"أصوات الإشعار"</string> <string name="ringtone_unknown" msgid="3914515995813061520">"غير معروف"</string> <plurals name="wifi_available" formatted="false" msgid="7900333017752027322"> - <item quantity="zero">لا تتوفر أية شبكات Wi-Fi</item> + <item quantity="zero">لا تتوفر أي شبكات Wi-Fi</item> <item quantity="two">تتوفر شبكتا Wi-Fi</item> <item quantity="few">تتوفر شبكات Wi-Fi</item> <item quantity="many">تتوفر شبكات Wi-Fi</item> @@ -1194,7 +1194,7 @@ <item quantity="one">تتوفر شبكة Wi-Fi واحدة</item> </plurals> <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606"> - <item quantity="zero">لا تتوفر أية شبكات Wi-Fi مفتوحة</item> + <item quantity="zero">لا تتوفر أي شبكات Wi-Fi مفتوحة</item> <item quantity="two">تتوفر شبكتا Wi-Fi مفتوحتان</item> <item quantity="few">تتوفر شبكات Wi-Fi مفتوحة</item> <item quantity="many">تتوفر شبكات Wi-Fi مفتوحة</item> @@ -1413,7 +1413,7 @@ <string name="back_button_label" msgid="2300470004503343439">"رجوع"</string> <string name="next_button_label" msgid="1080555104677992408">"التالي"</string> <string name="skip_button_label" msgid="1275362299471631819">"تخطي"</string> - <string name="no_matches" msgid="8129421908915840737">"ليس هناك أية مطابقات"</string> + <string name="no_matches" msgid="8129421908915840737">"ليس هناك أي مطابقات"</string> <string name="find_on_page" msgid="1946799233822820384">"بحث في الصفحة"</string> <plurals name="matches_found" formatted="false" msgid="1210884353962081884"> <item quantity="zero"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item> @@ -1947,4 +1947,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"تعذّرت استعادة الاختصار لأن التطبيق لا يوفِّر إمكانية النسخ الاحتياطي والاستعادة"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"تعذّرت استعادة الاختصار بسبب عدم تطابق توقيع التطبيق"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"تعذّرت استعادة الاختصار"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index a05d49f72e42..8069d6c82c94 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Qısayolu bərpa etmək mümkün olmadı, çünki tətbiq yedəkləməni və bərpa etməyi dəstəkləmir"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tətbiqin imza uyğunsuzluğu səbəbilə qısayolu bərpa etmək mümkün olmadı"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Qısayolu bərpa etmək mümkün olmadı"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index ce220dbeea4c..bb5a4040361b 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1842,4 +1842,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečice nije uspelo jer aplikacija ne podržava pravljenje rezervne kopije i vraćanje"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečice nije uspelo jer se potpisi aplikacija ne podudaraju"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečice nije uspelo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index f636f488b79f..b5e28b3a50c4 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не атрымалася аднавіць ярлык, бо праграма не падтрымлівае рэзервовае капіраванне і аднаўленне"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не атрымалася аднавіць ярлык з-за несупадзення подпісаў праграм"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не атрымалася аднавіць ярлык"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 7a3793926b2b..e069c4e9df9c 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Прекият път не можа да бъде възстановен, защото приложението не поддържа създаването на резервно копие и възстановяването"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Прекият път не можа да бъде възстановен поради несъответствие в подписа на приложението"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Прекият път не можа да бъде възстановен"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index b88d2c8321fd..9b1f6c38e613 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপটিতে \'ব্যাক-আপ এবং রিস্টোর\' করার সুবিধা নেই"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"শর্টকাট ফিরিয়ে আনা যায়নি কারণ অ্যাপের সিগ্নেচারটি মিল হচ্ছে না"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"শর্টকাট ফিরিয়ে আনা যায়নি"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index e19a974a10c0..c79566bff15d 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1844,4 +1844,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Prečica nije uspješno vraćena jer aplikacija ne podržava izradu sigurnosne kopije i vraćanje"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Prečica nije uspješno vraćena zbog nepodudaranja potpisa aplikacije"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Prečica nije uspješno vraćena"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 7e109acd247c..ea0900836d04 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No s\'ha pogut restaurar la drecera perquè l\'aplicació no permet la còpia de seguretat ni la restauració"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No s\'ha pogut restaurar la drecera perquè la signatura de l\'aplicació no coincideix"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No s\'ha pogut restaurar la drecera"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 8b0e46e3e7a9..684c2574e475 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Zkratku nelze obnovit, protože aplikace nepodporuje zálohování a obnovu"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Zkratku nelze obnovit, protože se neshoduje podpis aplikace"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Zkratku nelze obnovit"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 0be9d20e8732..90b7e5ed570c 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter backup og gendannelse"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 367949cc3ce9..9d317eb410ac 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App keine Sicherung und keine Wiederherstellung unterstützt"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Verknüpfung konnte nicht wiederhergestellt werden, weil die App-Signatur nicht übereinstimmt"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Verknüpfung konnte nicht wiederhergestellt werden"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 05c51cfa1ec4..9aa3eb56a087 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, επειδή η εφαρμογή δεν υποστηρίζει τη δημιουργία αντιγράφων ασφαλείας και την επαναφορά"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης, λόγω αναντιστοιχίας της υπογραφής εφαρμογής"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Δεν ήταν δυνατή η επαναφορά της συντόμευσης"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index ed975636e38a..700641edb4a1 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index ed975636e38a..700641edb4a1 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index ed975636e38a..700641edb4a1 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index ed975636e38a..700641edb4a1 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 2833630c7a22..ba21245b1f9a 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 3efbad9585a2..1fe3c9a2d9eb 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Error al restablecer el acceso directo porque la app no admite la opción de copia de seguridad y restauración"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Error al restablecer el acceso directo por falta de coincidencia con la firma de apps"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Error al restablecer el acceso directo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 5a0a118914d3..cf25ed3ab72b 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -453,7 +453,7 @@ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Permite que la aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos y que realice cambios en la configuración de redes Wi-Fi del dispositivo."</string> <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string> <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al tablet. Utiliza más batería que el modo de no multidifusión."</string> - <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos a través de una red Wi-Fi mediante direcciones de multidifusión, no solo la TV. Consume más energía que el modo sin multidifusión."</string> + <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos a través de una red Wi-Fi mediante direcciones de multidifusión, no solo la TV. Consume más batería que el modo sin multidifusión."</string> <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al teléfono. Utiliza más batería que el modo de no multidifusión."</string> <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"acceder a los ajustes de Bluetooth"</string> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string> @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"No se ha podido restaurar el acceso directo porque la aplicación no es compatible con la función de copia de seguridad y restauración"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"No se ha podido restaurar el acceso directo porque la firma de la aplicación no coincide"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"No se ha podido restaurar el acceso directo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 4b2d13b472ca..c0821c790e91 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Otseteed ei õnnestunud taastada, kuna rakendus ei toeta varundamist ega taastamist"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Otseteed ei õnnestunud taastada, kuna rakenduse allkiri ei ühti"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Otseteed ei õnnestunud taastada"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index f468b5d0b90d..100ed1ef17fb 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -294,7 +294,7 @@ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu \"Arakatu ukituta\""</string> - <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Sakatutako elementuak ozen esango dira eta pantaila keinu bidez arakatu ahal izango da."</string> + <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Sakatutako elementuak ozen irakurriko dira eta pantaila keinu bidez arakatu ahal izango da."</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Behatu idazten duzun testua"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ez da salbuespenik egiten datu pertsonalekin, hala nola, kreditu-txartelen zenbakiekin eta pasahitzekin."</string> <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolatu pantailaren zoom-maila"</string> @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ezin izan da leheneratu lasterbidea aplikazioak ez duelako onartzen babeskopiak egiteko eta leheneratzeko aukera"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ezin izan da leheneratu lasterbidea aplikazioaren sinadurak ez datozelako bat"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ezin izan da leheneratu lasterbidea"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 806196219912..045833630bc7 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"نمیتوان میانبر را بازیابی کرد زیرا برنامه از پشتیبانگیری و بازیابی پشتیبانی نمیکند"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"بهعلت عدم تطابق امضای برنامه نمیتوان میانبر را بازیابی کرد"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"نمیتوان میانبر را بازیابی کرد"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 43854663cee8..d6d131569e49 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Pikakuvakkeen palautus epäonnistui, koska sovellus ei tue varmuuskopiointia eikä palauttamista."</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Pikakuvakkeen palautus epäonnistui sovelluksen allekirjoituksen yhteensopimattomuuden vuoksi."</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Pikakuvakkeen palautus epäonnistui."</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 49a3640200c2..9af3ed74eb8a 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 5564d8bef9a5..97cc0ec476f9 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Le raccourci ne peut pas être restauré car l\'application n\'accepte pas la sauvegarde et la restauration"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Le raccourci ne peut pas être restauré car la signature de l\'application est différente"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 40dff7e72f6a..a53fac7d2c41 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -133,7 +133,7 @@ <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string> <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wifi preferida"</string> <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datos móbiles preferidos"</string> - <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Só wifi"</string> + <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Só por wifi"</string> <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string> <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> tras <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string> @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Non se puido restaurar o atallo porque a aplicación non é compatible coa restauración e a copia de seguranza"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Non se puido restaurar o atallo porque a sinatura da aplicación non coincide"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Non se puido restaurar o atallo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 7a4c1b2f6beb..81e5f4f9bae0 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપ બૅકઅપ અને ફરી મેળવવાનું સમર્થન કરતી નથી"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"શૉર્ટકટ ફરી મેળવી શકાયો નથી કારણ કે ઍપમાં છે તે સહી મેળ ખાતી નથી"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"શૉર્ટકટ પાછો મેળવી શકાયો નથી"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index adeba4ed5c86..234958368279 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"शॉर्टकट बहाल नहीं किया जा सका क्योंकि इस ऐप में बैकअप लेने और उसे बहाल करने की सुविधा नहीं है"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ऐप सिग्नेचर अलग होने के कारण शॉर्टकट बहाल नहीं किया जा सका"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट बहाल नहीं किया जा सका"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 688376952824..bbe7ca96f167 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1842,4 +1842,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Vraćanje prečaca nije uspjelo jer aplikacija ne podržava sigurnosno kopiranje i vraćanje"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Vraćanje prečaca nije uspjelo zbog nepodudaranja potpisa aplikacije"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Vraćanje prečaca nije uspjelo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 2545283be5d8..2dbe49d1c836 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás nem támogatja a biztonsági mentést és visszaállítást"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nem sikerült visszaállítani a parancsikont, mert az alkalmazás-aláírás nem egyezik"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nem sikerült visszaállítani a parancsikont"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index d29c35791941..1218b486f38e 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածում չի աջակցվում պահուստավորման և վերականգնման գործառույթը"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Չհաջողվեց վերականգնել դյուրանցումը"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index d5d8d998b6b2..cb2b8a5352d9 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan karena aplikasi tidak mendukung backup dan pulihkan"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan karena tanda tangan aplikasi tidak cocok"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan."</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index b65da75b1b70..40bf34c6c03a 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ekki var hægt að endurheimta flýtileið vegna þess að forritið styður ekki öryggisafritun og endurheimt"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ekki var hægt að endurheimta flýtileið vegna þess að undirskriftir forrita passa ekki saman"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ekki var hægt að endurheimta flýtileið"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 0f36301d1d9a..3c9745f7500f 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossibile ripristinare la scorciatoia perché l\'app non supporta il backup e il ripristino"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossibile ripristinare la scorciatoia perché la firma dell\'app non corrisponde"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossibile ripristinare la scorciatoia"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index a1528403b2af..7c0ce3a7ac3a 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"לא ניתן היה לשחזר את קיצור הדרך מפני שהאפליקציה אינה תומכת בגיבוי ובשחזור"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"לא ניתן היה לשחזר את קיצור הדרך עקב חוסר התאמה בחתימה על האפליקציות"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"לא ניתן היה לשחזר את קיצור הדרך"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 2f11776e44c5..2fb35f8a5ac0 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"このアプリはバックアップと復元に対応していないため、ショートカットを復元できませんでした"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"アプリの署名が一致しないため、ショートカットを復元できませんでした"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ショートカットを復元できませんでした"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 40e9414e3057..45ed4662bf95 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"მალსახმობის აღდგენა ვერ მოხერხდა, რადგან ამ აპის მიერ მხარდაუჭერელია სარეზერვო ასლით აღდგენა"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"მალსახმობის აღდგენა ვერ მოხერხდა აპის ხელმოწერის შეუსაბამობის გამო"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"მალსახმობის აღდგენა ვერ მოხერხდა"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index d428ff08ca4e..51c51477526b 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Қолданба сақтық көшірме жасау мен қалпына келтіруді қолдамайтындықтан, таңбаша қалпына келтірілмеді"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Қолтаңба сәйкес келмейтіндіктен, таңбаша қалпына келтірілмеді"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Таңбаша қалпына келтірілмеді"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 889ea5ea3ccc..c266416724a2 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1809,4 +1809,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារកម្មវិធីមិនស្គាល់ការបម្រុងទុក និងការស្តារ"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"មិនអាចស្តារផ្លូវកាត់បានទេ ដោយសារការស៊ីញ៉េកម្មវិធីមិនត្រូវគ្នា"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"មិនអាចស្តារផ្លូវកាត់បានទេ"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index d751c1302589..2fe14dc9342a 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ಅಪ್ಲಿಕೇಶನ್ ಬ್ಯಾಕಪ್ ಮತ್ತು ಪುನಃಸ್ಥಾಪನೆಯನ್ನು ಬೆಂಬಲಿಸದಿರುವುದರಿಂದ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಪುನಃಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ಅಪ್ಲಿಕೇಶನ್ ಸಹಿ ಹೊಂದಿಕೆಯಾಗದ ಕಾರಣದಿಂದ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಪುನಃಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಪುನಃ ಸ್ಥಾಪನೆ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 922f02facd4c..221a233e6eac 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"앱이 백업 및 복원을 지원하지 않으므로 바로가기를 복원할 수 없습니다"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"앱 서명이 일치하지 않아 바로가기를 복원할 수 없습니다"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"바로가기를 복원할 수 없습니다"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index f3f7222725b4..1bce4910cdcc 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1809,4 +1809,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Колдонмо камдык көчүрмөнү сактоо жана калыбына келтирүү функцияларын колдобогондуктан кыска жол калыбына келтирилбей койду"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Колдонмонун колтамгасы дал келбегендиктен кыска жол калыбына келтирилбей койду"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Кыска жол калыбына келтирилбей койду"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index bc7e33913960..9f7a28fe2036 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ບໍ່ສາມາດກູ້ທາງລັດຂຶ້ນມາໄດ້ເນື່ອງຈາກແອັບບໍ່ຮອງຮັບການສຳຮອງ ແລະ ກູ້ຂໍ້ມູນ"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້ເນື່ອງຈາກລາຍເຊັນແອັບບໍ່ກົງກັນ"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ບໍ່ສາມາດກູ້ທາງລັດຄືນມາໄດ້"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 2f5014ea27df..57745c273a0d 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nepavyko atkurti sparčiojo klavišo, nes programa nepalaiko atsarginės kopijos kūrimo ir atkūrimo funkcijų"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nepavyko atkurti sparčiojo klavišo, nes programos parašas neatitinka"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nepavyko atkurti sparčiojo klavišo"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index c2199a8e9bf1..2d98ade4d39a 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1842,4 +1842,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nevarēja atjaunot saīsni, jo lietotnē netiek atbalstīta dublēšana un atjaunošana."</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Saīsni nevarēja atjaunot lietotnes paraksta neatbilstības dēļ."</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nevarēja atjaunot saīsni."</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index e1e2b43245a7..67aabea38216 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1810,4 +1810,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не можеше да се врати кратенката бидејќи апликацијата не поддржува бекап и враќање"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не можеше да се врати кратенката бидејќи потписот на апликацијата не се совпаѓа"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не можеше да се врати кратенката"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 6a8cea195d89..69c0fedac4ce 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ആപ്പ് \'ബാക്കപ്പും പുനഃസ്ഥാപിക്കലും\' പിന്തുണയ്ക്കാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ആപ്പ് സിഗ്നേച്ചർ പൊരുത്തപ്പെടാത്തതിനാൽ കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"കുറുക്കുവഴി പുനഃസ്ഥാപിക്കാനായില്ല"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 53740f949b21..dbbb29e68f0d 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1805,4 +1805,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Апп нөөцлөлт, сэргээлтийг дэмждэггүй тул товчлолыг сэргээж чадсангүй"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Аппын гарын үсэг таарахгүй байгаа тул товчлолыг сэргээж чадсангүй"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Товчлолыг сэргээж чадсангүй"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 398ad0dda7cc..addb2d18466f 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अॅप बॅकअप आणि रिस्टोअर करण्यास सपोर्ट देत नसल्यामुळे शॉर्टकट रिस्टोअर करू शकलो नाही"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अॅप स्वाक्षरी न जुळल्यामुळे शॉर्टकट रिस्टोअर करू शकलो नाही"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"शॉर्टकट रिस्टोअर करू शकलो नाही"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 574c77527dcc..f7e18ffc1518 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Tidak dapat memulihkan pintasan kerana apl tidak menyokong sandaran dan segerakan"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Tidak dapat memulihkan pintasan kerana ketakpadanan tandatangan apl"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Tidak dapat memulihkan pintasan"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 9dc49cf6222a..1777b26066d5 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"အက်ပ်သည် မိတ္တူကူးခြင်းနှင့် ပြန်ယူခြင်းကို ပံ့ပိုးခြင်းမရှိသည့်အတွက် ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"အက်ပ်လက်မှတ် မတူညီသည့်အတွက် ဖြတ်လမ်းလင့်ခ်များကို ပြန်ယူ၍မရပါ"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ဖြတ်လမ်းလင့်ခ်ကို ပြန်ယူ၍မရပါ"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d360fa444842..873967a8d067 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kunne ikke gjenopprette snarveien fordi appen ikke støtter sikkerhetskopiering og gjenoppretting"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kunne ikke gjenopprette snarveien på grunn av manglende samsvar for appsignaturen"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kunne ikke gjenopprette snarveien"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 3d05239c45c2..3e0e04bdb555 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1813,4 +1813,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"अनुप्रयोगले ब्याकअप तथा पुनर्स्थापनालाई समर्थन नगर्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"अनुप्रयोगमा प्रयोग गरिने हस्ताक्षर नमिल्ने हुँदा सर्टकट पुनर्स्थापित गर्न सकिएन"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"सर्टकट पुनर्स्थापित गर्न सकिएन"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 725fe8ec2cbd..1d8619c54fd1 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Kan snelkoppeling niet herstellen omdat de app geen ondersteuning biedt voor \'Back-up maken en terugzetten\'"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Kan snelkoppeling niet herstellen vanwege een niet-overeenkomende app-ondertekening"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kan snelkoppeling niet herstellen"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index cf90550a4ddf..b08b1b2e815f 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ ਕਿਉਂਕਿ ਐਪ \'ਬੈਕਅੱਪ ਅਤੇ ਮੁੜ-ਬਹਾਲੀ\' ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰਦੀ"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ਐਪ ਹਸਤਾਖਰ ਦਾ ਮੇਲ ਨਾ ਹੋਣ ਕਾਰਨ ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ਸ਼ਾਰਟਕੱਟ ਮੁੜ-ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 412d5a74ecf5..108b87be696a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nie można przywrócić skrótu, bo aplikacja nie obsługuje tworzenia i przywracania kopii zapasowej"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nie można przywrócić skrótu z powodu niezgodności podpisu aplikacji"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nie można przywrócić skrótu"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index bf83d777f9ba..35cbd285003b 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 31b67a08288c..a9a4a9115bdb 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque a aplicação não é compatível com a funcionalidade de cópia de segurança e restauro."</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido a uma falha de correspondência entre as assinaturas das aplicações."</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho."</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index bf83d777f9ba..35cbd285003b 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Não foi possível restaurar o atalho porque o app não é compatível com backup e restauração"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Não foi possível restaurar o atalho devido à incompatibilidade de assinatura de apps"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Não foi possível restaurar o atalho"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 4f15c33b5454..010489412fbf 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1842,4 +1842,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nu s-a putut restabili comanda rapidă deoarece aplicația nu acceptă backupul și restabilirea"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nu s-a putut restabili comanda rapidă din cauza nepotrivirii semnăturii aplicației"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nu s-a putut restabili comanda rapidă"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 60ad4413fa76..460e0c75a72c 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не удалось восстановить ярлык: приложение не поддерживает резервное копирование"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не удалось восстановить ярлык: некорректная подпись приложения"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не удалось восстановить ярлык"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 5b0eda333ec7..4188a4176fb7 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1809,4 +1809,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"යෙදුම උපස්ථ සහ ප්රතිසාධනය සඳහා සහාය නොදක්වන බැවින් කෙටි මග ප්රතිසාධනය කළ නොහැකි විය"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"යෙදුම් අත්සන නොගැළපෙන බැවින් කෙටි මග ප්රතිසාධනය කළ නොහැකි විය"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"කෙටි මග ප්රතිසාධනය කළ නොහැකි විය"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 1f11fb464434..1fb90ffa22df 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Odkaz sa nepodarilo obnoviť, pretože aplikácia nepodporuje zálohovanie a obnovu"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Odkaz sa nepodarilo obnoviť pre nesúlad podpisov aplikácie"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Odkaz sa nepodarilo obnoviť"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e8f89a5b6672..df3c3e77990d 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Bližnjice ni bilo mogoče obnoviti, ker aplikacija ne podpira varnostnega kopiranja in obnavljanja"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Bližnjice ni bilo mogoče obnoviti zaradi neujemanja podpisa aplikacije"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Bližnjice ni bilo mogoče obnoviti"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index a03ac240cabe..e6d60d45d8ee 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Nuk mund të restaurohej shkurtorja sepse aplikacioni nuk mbështet rezervimin dhe restaurimin"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Nuk mund të restaurohej shkurtorja për shkak të mospërputhjes së nënshkrimit të aplikacionit"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Nuk mund të restaurohej shkurtorja"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 8bec119cca5c..275db372f635 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1842,4 +1842,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Враћање пречице није успело јер апликација не подржава прављење резервне копије и враћање"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Враћање пречице није успело јер се потписи апликација не подударају"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Враћање пречице није успело"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 1f590d30ac68..1633e4302e86 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1205,7 +1205,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Ett tillbehör med analog ljudutgång hittades"</string> <string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Den anslutna enheten är inte kompatibel med mobilen. Tryck här om du vill veta mer."</string> <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string> - <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string> + <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck för att inaktivera USB-felsökning."</string> <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj för att inaktivera USB-felsökning."</string> <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string> <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string> @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Det gick inte att återställa genvägen eftersom appen inte har stöd för säkerhetskopiering och återställning"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Det gick inte att återställa genvägen eftersom appens signatur inte stämmer"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Det gick inte att återställa genvägen"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index bd8b0295aa9e..b98a5c7c5b7e 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1805,4 +1805,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Imeshindwa kurejesha njia ya mkato kwa sababu programu haitumii kipengele cha hifadhi rudufu na kurejesha upya"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Imeshindwa kurejesha njia ya mkato kwa sababu ufunguo wako wa kuambatisha cheti kwenye programu haulingani"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Imeshindwa kurejesha njia ya mkato"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 6d247f4c53f6..6014de4e4df5 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"காப்புப் பிரதி மற்றும் மீட்டமைவைப் பயன்பாடு ஆதரிக்காத காரணத்தால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"பயன்பாட்டுச் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index d39467be1bfc..a04c5290052f 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"బ్యాకప్ మరియు పునరుద్ధరణకు యాప్ మద్దతు ఇవ్వని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"యాప్ సంతకం సరిపోలని కారణంగా సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"సత్వరమార్గాన్ని పునరుద్ధరించడం సాధ్యపడలేదు"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 1bea4e4074e6..d9a504b8c3d4 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"คืนค่าทางลัดไม่ได้เนื่องจากแอปไม่รองรับการสำรองข้อมูลและคืนค่า"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"คืนค่าทางลัดไม่ได้เนื่องจากการลงนามแอปไม่ตรงกัน"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"คืนค่าทางลัดไม่ได้"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 2bc57804e0ad..98e169e8cfb6 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Hindi ma-restore ang shortcut dahil hindi sinusuportahan ng app ang pag-back up at pag-restore"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Hindi ma-restore ang shortcut dahil hindi magkatugma ang signature ng app"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Hindi ma-restore ang shortcut"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 337d458ab240..e2b1cb3ca863 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Uygulama, yedekleme ve geri yüklemeyi desteklemediğinden kısayol geri yüklenemedi"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Uygulama imzası eşleşmediğinden kısayol geri yüklenemedi"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Kısayol geri yüklenemedi"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 5344dcf793ef..788444e99530 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1877,4 +1877,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Не вдалося відновити ярлик, оскільки додаток не підтримує резервне копіювання та відновлення"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Не вдалося відновити ярлик, оскільки підписи додатків не збігаються"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Не вдалося відновити ярлик"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 4ced9cf94212..38313d6e5982 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"شارٹ کٹ کو بحال نہیں کیا جا سکا، کیونکہ ایپ بیک اپ اور بحالی کو سپورٹ نہیں کرتی ہے"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ایپ دستخط غیر مماثل ہونے کی وجہ سے شارٹ کٹ کو بحال نہیں کیا جا سکا"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"شارٹ کٹ کو بحال نہیں کیا جا سکا"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index d7d3941b8912..92ec3540008a 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1808,4 +1808,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ilovada zaxiralash va tiklash ishlamagani uchun yorliq tiklanmadi"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ilova imzosi mos kelmagani uchun yorliq tiklanmadi"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Yorliq tiklanmadi"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index c5a370a53bad..f5a19725a321 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Không thể khôi phục lối tắt do ứng dụng không hỗ trợ sao lưu và khôi phục"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Không thể khôi phục lối tắt do không khớp chữ ký ứng dụng"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Không thể khôi phục lối tắt"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index e8ad01548fa6..70b299e18aad 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"无法恢复快捷方式,因为应用不支持备份和恢复功能"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"无法恢复快捷方式,因为应用签名不相符"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"无法恢复快捷方式"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index bedaef486b0f..3dad72480a97 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"由於應用程式不支援備份和還原功能,因此無法還原捷徑"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"由於應用程式簽署不相符,因此無法還原捷徑"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 38109f85babe..d3ad7b07cbdc 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"應用程式不支援備份與還原功能,因此無法還原捷徑"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"應用程式簽署不相符,因此無法還原捷徑"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"無法還原捷徑"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 57b9fc36f6c7..e91e382a85d9 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1807,4 +1807,6 @@ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ayikwazanga ukubuyisa isinqamuleli ngoba uhlelo lokusebenza alusekeli isipele nokubuyisa"</string> <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ayikwazanga ukubuyisa isinqamuleli ngoba isignisha yohlelo lokusebenza ayifani"</string> <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ayikwazanga ukubuyisa isinqamuleli"</string> + <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) --> + <skip /> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 9929545c70cf..2c824ea01be7 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -152,11 +152,11 @@ <dimen name="dialog_padding">16dp</dimen> <!-- The margin on the start of the content view --> - <dimen name="notification_content_margin_start">24dp</dimen> + <dimen name="notification_content_margin_start">16dp</dimen> <!-- The margin on the end of the content view Keep in sync with notification_content_plus_picture_margin! --> - <dimen name="notification_content_margin_end">24dp</dimen> + <dimen name="notification_content_margin_end">16dp</dimen> <!-- The margin on the end of the content view with a picture. Keep in sync with notification_content_plus_picture_margin! --> @@ -166,7 +166,7 @@ content end margin. Keep equal to (notification_content_picture_margin + notification_content_margin_end)! --> - <dimen name="notification_content_plus_picture_margin_end">80dp</dimen> + <dimen name="notification_content_plus_picture_margin_end">72dp</dimen> <!-- The additional margin on the sides of the ambient view. --> <dimen name="notification_extra_margin_ambient">16dp</dimen> @@ -175,10 +175,10 @@ <dimen name="notification_action_list_height">56dp</dimen> <!-- height of the content margin to accomodate for the header --> - <dimen name="notification_content_margin_top">41.5dp</dimen> + <dimen name="notification_content_margin_top">46dp</dimen> <!-- height of the content margin on the bottom --> - <dimen name="notification_content_margin_bottom">18dp</dimen> + <dimen name="notification_content_margin_bottom">20dp</dimen> <!-- The height of the progress bar. --> <dimen name="notification_progress_bar_height">15dp</dimen> @@ -187,7 +187,7 @@ <dimen name="notification_progress_margin_top">8dp</dimen> <!-- height of the notification header (for icon and package name) --> - <dimen name="notification_header_height">54dp</dimen> + <dimen name="notification_header_height">50dp</dimen> <!-- The height of the background for a notification header on a group --> <dimen name="notification_header_background_height">49.5dp</dimen> @@ -199,7 +199,7 @@ <dimen name="notification_header_padding_bottom">16dp</dimen> <!-- The margin at the bottom of the notification header. --> - <dimen name="notification_header_margin_bottom">5dp</dimen> + <dimen name="notification_header_margin_bottom">0dp</dimen> <!-- The end margin after the application icon in the notification header --> <dimen name="notification_header_icon_margin_end">3dp</dimen> @@ -250,7 +250,7 @@ <dimen name="media_notification_expanded_image_margin_bottom">20dp</dimen> <!-- The absolute height for the header in a media notification. --> - <dimen name="media_notification_header_height">53dp</dimen> + <dimen name="media_notification_header_height">@dimen/notification_header_height</dimen> <!-- The margin of the content to an image--> <dimen name="notification_content_image_margin_end">8dp</dimen> @@ -590,7 +590,7 @@ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.--> <dimen name="notification_media_image_max_width">280dp</dimen> <!-- The size of the right icon --> - <dimen name="notification_right_icon_size">40dp</dimen> + <dimen name="notification_right_icon_size">38dp</dimen> <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. --> <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen> @@ -607,7 +607,7 @@ <!-- The size of the right icon image when on low ram --> <dimen name="notification_right_icon_size_low_ram">40dp</dimen> - <dimen name="messaging_avatar_size">24dp</dimen> + <dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen> <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height --> <dimen name="autofill_dataset_picker_max_size">90%</dimen> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index def650a579ca..fa3cf2f48dae 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -502,20 +502,17 @@ please see styles_device_defaults.xml. <style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" /> <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Light.TextView"> - <item name="layout_width">match_parent</item> + <item name="layout_width">wrap_content</item> <item name="layout_height">wrap_content</item> <item name="ellipsize">end</item> <item name="textAppearance">@style/TextAppearance.Material.Notification</item> - <item name="background">@drawable/messaging_message_background</item> </style> <style name="Widget.Material.Notification.MessagingName" parent="Widget.Material.Light.TextView"> <item name="layout_width">wrap_content</item> <item name="layout_height">wrap_content</item> <item name="ellipsize">end</item> - <item name="textAppearance">@style/TextAppearance.Material.Notification</item> - <item name="textColor">@color/notification_primary_text_color_light</item> - <item name="textSize">12sp</item> + <item name="textAppearance">@style/TextAppearance.Material.Notification.Title</item> </style> <!-- Widget Styles --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2f2566cd4a36..d2ad99b4b744 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2608,10 +2608,12 @@ <java-symbol type="string" name="notification_hidden_text" /> <java-symbol type="id" name="app_name_text" /> <java-symbol type="id" name="header_text" /> + <java-symbol type="id" name="header_text_secondary" /> <java-symbol type="id" name="expand_button" /> <java-symbol type="id" name="notification_header" /> <java-symbol type="id" name="time_divider" /> <java-symbol type="id" name="header_text_divider" /> + <java-symbol type="id" name="header_text_secondary_divider" /> <java-symbol type="id" name="text_line_1" /> <java-symbol type="drawable" name="ic_expand_notification" /> <java-symbol type="drawable" name="ic_collapse_notification" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 7cfedc8a1f52..68789f334a81 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -211,6 +211,7 @@ public class SettingsBackupTest { Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS, Settings.Global.FANCY_IME_ANIMATIONS, Settings.Global.FORCE_ALLOW_ON_EXTERNAL, + Settings.Global.FORCED_APP_STANDBY_ENABLED, Settings.Global.FSTRIM_MANDATORY_INTERVAL, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, Settings.Global.GLOBAL_HTTP_PROXY_HOST, diff --git a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml index 4d4d6befce97..810b1e7a4754 100644 --- a/packages/BackupRestoreConfirmation/res/values-ar/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-ar/strings.xml @@ -21,7 +21,7 @@ <string name="backup_confirm_text" msgid="1878021282758896593">"تم طلب الاحتفاظ بنسخة احتياطية كاملة من البيانات على كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاحتفاظ بنسخة احتياطية بنفسك، فلا تسمح بمتابعة العملية."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"الاحتفاظ بنسخة احتياطية من بياناتي"</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"عدم النسخ الاحتياطي"</string> - <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أية بيانات حاليًا على الجهاز."</string> + <string name="restore_confirm_text" msgid="7499866728030461776">"تم طلب استرداد جميع البيانات بالكامل من كمبيوتر سطح مكتب متصل. هل تريد السماح بإجراء ذلك؟\n\nإذا لم تطلب الاسترداد بنفسك، فلا تسمح بمتابعة العملية. يؤدي لك إلى استبدال أي بيانات حاليًا على الجهاز."</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"استرداد بياناتي"</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"عدم الاسترداد"</string> <string name="current_password_text" msgid="8268189555578298067">"يُرجى إدخال كلمة مرور النسخ الاحتياطي أدناه:"</string> diff --git a/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml index cbc579e18a0a..baa4867ec433 100644 --- a/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-pt-rBR/strings.xml @@ -18,10 +18,10 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string> <string name="restore_confirm_title" msgid="5469365809567486602">"Restauração completa"</string> - <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string> + <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Quer permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer backup de meus dados"</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer backup"</string> - <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string> + <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Quer permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar meus dados"</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string> <string name="current_password_text" msgid="8268189555578298067">"Digite sua senha de backup atual abaixo:"</string> diff --git a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml index cbc579e18a0a..baa4867ec433 100644 --- a/packages/BackupRestoreConfirmation/res/values-pt/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-pt/strings.xml @@ -18,10 +18,10 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="backup_confirm_title" msgid="827563724209303345">"Backup completo"</string> <string name="restore_confirm_title" msgid="5469365809567486602">"Restauração completa"</string> - <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Deseja permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string> + <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitado um backup completo de todos os dados para um computador conectado. Quer permitir que isso aconteça?\n\nCaso você não tenha solicitado o backup, não permita que a operação prossiga."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer backup de meus dados"</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer backup"</string> - <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Deseja permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string> + <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitada uma restauração completa de todos os dados de um computador conectado. Quer permitir que isso ocorra?\n\nCaso você não tenha solicitado a restauração, não permita que a operação prossiga. Isso substituirá todos os dados existentes no dispositivo!"</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar meus dados"</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string> <string name="current_password_text" msgid="8268189555578298067">"Digite sua senha de backup atual abaixo:"</string> diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml index 530efc032cd7..ed75344d7fbb 100644 --- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string> <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string> - <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala rudufu kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa sio wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string> + <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa si wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string> <string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string> diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml index 7edbb119f67c..ad2fc24891f1 100644 --- a/packages/CarrierDefaultApp/res/values-bs/strings.xml +++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml @@ -4,12 +4,12 @@ <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string> <string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string> <string name="portal_notification_id" msgid="5155057562457079297">"Mobilni internet je potrošen"</string> - <string name="no_data_notification_id" msgid="668400731803969521">"Prijenos mobilnih podataka je deaktiviran"</string> + <string name="no_data_notification_id" msgid="668400731803969521">"Prijenos podataka na mobilnoj mreži je deaktiviran"</string> <string name="portal_notification_detail" msgid="2295729385924660881">"Dodirnite da posjetite %s web lokaciju"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"Obratite se pružaocu usluga %s"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nema mobilnog prijenosa podataka"</string> <string name="no_mobile_data_connection" msgid="544980465184147010">"Dodajte plan prijenosa podataka ili rominga putem operatera %s"</string> - <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status mobilnih podataka"</string> + <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status prijenosa podataka na mobilnoj mreži"</string> <string name="action_bar_label" msgid="4290345990334377177">"Prijava na mobilnu mrežu"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string> <string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string> diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml index 9217bc49a21c..8f37882a861d 100644 --- a/packages/InputDevices/res/values-en-rAU/strings.xml +++ b/packages/InputDevices/res/values-en-rAU/strings.xml @@ -42,4 +42,5 @@ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string> + <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string> </resources> diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml index 9217bc49a21c..8f37882a861d 100644 --- a/packages/InputDevices/res/values-en-rCA/strings.xml +++ b/packages/InputDevices/res/values-en-rCA/strings.xml @@ -42,4 +42,5 @@ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string> + <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string> </resources> diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml index 9217bc49a21c..8f37882a861d 100644 --- a/packages/InputDevices/res/values-en-rGB/strings.xml +++ b/packages/InputDevices/res/values-en-rGB/strings.xml @@ -42,4 +42,5 @@ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string> + <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string> </resources> diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml index 9217bc49a21c..8f37882a861d 100644 --- a/packages/InputDevices/res/values-en-rIN/strings.xml +++ b/packages/InputDevices/res/values-en-rIN/strings.xml @@ -42,4 +42,5 @@ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string> + <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string> </resources> diff --git a/packages/InputDevices/res/values-en-rXC/strings.xml b/packages/InputDevices/res/values-en-rXC/strings.xml index 43d76770a522..bc1b234344ec 100644 --- a/packages/InputDevices/res/values-en-rXC/strings.xml +++ b/packages/InputDevices/res/values-en-rXC/strings.xml @@ -42,4 +42,5 @@ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Latvian"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persian"</string> + <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijani"</string> </resources> diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml index eab784db0e20..f1fd93b4f6b2 100644 --- a/packages/PrintSpooler/res/values-ar/strings.xml +++ b/packages/PrintSpooler/res/values-ar/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string> <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="zero">لم يتم العثور على أية طابعة (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item> + <item quantity="zero">لم يتم العثور على أي طابعة (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item> <item quantity="two">تم العثور على طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item> <item quantity="few">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item> <item quantity="many">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item> diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml index 862d19305d91..7fe9c8c5d4cd 100644 --- a/packages/PrintSpooler/res/values-mr/strings.xml +++ b/packages/PrintSpooler/res/values-mr/strings.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="4469836075319831821">"स्पूलर मुद्रण"</string> + <string name="app_label" msgid="4469836075319831821">"स्पूलर प्रिंट"</string> <string name="more_options_button" msgid="2243228396432556771">"अधिक पर्याय"</string> <string name="label_destination" msgid="9132510997381599275">"गंतव्यस्थान"</string> <string name="label_copies" msgid="3634531042822968308">"प्रती"</string> @@ -31,22 +31,22 @@ <string name="template_all_pages" msgid="3322235982020148762">"सर्व <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string> <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> ची श्रेणी"</string> <string name="pages_range_example" msgid="8558694453556945172">"उदा. 1—5,8,11—13"</string> - <string name="print_preview" msgid="8010217796057763343">"मुद्रण पूर्वावलोकन"</string> + <string name="print_preview" msgid="8010217796057763343">"प्रिंट पूर्वावलोकन"</string> <string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकनासाठी पीडीएफ व्ह्यूअर इंस्टॉल करा"</string> <string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग अॅप क्रॅश झाले"</string> - <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्युत्पन्न करत आहे"</string> + <string name="generating_print_job" msgid="3119608742651698916">"प्रिंट कार्य व्युत्पन्न करत आहे"</string> <string name="save_as_pdf" msgid="5718454119847596853">"पीडीएफ म्हणून सेव्ह करा"</string> <string name="all_printers" msgid="5018829726861876202">"सर्व प्रिंटर..."</string> - <string name="print_dialog" msgid="32628687461331979">"मुद्रण संवाद"</string> + <string name="print_dialog" msgid="32628687461331979">"प्रिंट संवाद"</string> <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string> <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g> पैकी <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> पृष्ठ"</string> <string name="summary_template" msgid="8899734908625669193">"सारांश, प्रती <xliff:g id="COPIES">%1$s</xliff:g>, कागद आकार <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string> <string name="expand_handle" msgid="7282974448109280522">"विस्तृत करण्याचे हँडल"</string> <string name="collapse_handle" msgid="6886637989442507451">"संक्षिप्त करण्याचे हँडल"</string> - <string name="print_button" msgid="645164566271246268">"मुद्रण करा"</string> + <string name="print_button" msgid="645164566271246268">"प्रिंट करा"</string> <string name="savetopdf_button" msgid="2976186791686924743">"पीडीएफ वर सेव्ह करा"</string> - <string name="print_options_expanded" msgid="6944679157471691859">"मुद्रण पर्याय विस्तृत झाले"</string> - <string name="print_options_collapsed" msgid="7455930445670414332">"मुद्रण पर्याय संक्षिप्त झाले"</string> + <string name="print_options_expanded" msgid="6944679157471691859">"प्रिंट पर्याय विस्तृत झाले"</string> + <string name="print_options_collapsed" msgid="7455930445670414332">"प्रिंट पर्याय संक्षिप्त झाले"</string> <string name="search" msgid="5421724265322228497">"शोध"</string> <string name="all_printers_label" msgid="3178848870161526399">"सर्व प्रिंटर"</string> <string name="add_print_service_label" msgid="5356702546188981940">"सेवा जोडा"</string> @@ -64,9 +64,9 @@ <string name="notification_channel_progress" msgid="872788690775721436">"प्रिंट कार्ये चालवणे"</string> <string name="notification_channel_failure" msgid="9042250774797916414">"अयशस्वी प्रिंट कार्ये"</string> <string name="could_not_create_file" msgid="3425025039427448443">"फाईल तयार करणेे शक्य झाले नाही"</string> - <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही मुद्रण सेवा अक्षम केल्या आहेत"</string> + <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही प्रिंट सेवा अक्षम केल्या आहेत"</string> <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string> - <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string> + <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही प्रिंट सेवा सक्षम केलेल्या नाहीत"</string> <string name="print_no_printers" msgid="4869403323900054866">"कोणतेही प्रिंटर आढळले नाही"</string> <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोडू शकत नाही"</string> <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोडण्यासाठी निवडा"</string> @@ -79,7 +79,7 @@ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item> </plurals> - <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करत आहे"</string> + <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट करत आहे"</string> <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करत आहे"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर एरर <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8f2068111cd8..a510c4a6c503 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -78,10 +78,10 @@ <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen> <!-- Height of a small notification in the status bar--> - <dimen name="notification_min_height">100dp</dimen> + <dimen name="notification_min_height">106dp</dimen> <!-- Increased height of a small notification in the status bar --> - <dimen name="notification_min_height_increased">140dp</dimen> + <dimen name="notification_min_height_increased">146dp</dimen> <!-- Height of a small notification in the status bar which was used before android N --> <dimen name="notification_min_height_legacy">64dp</dimen> @@ -90,7 +90,7 @@ <dimen name="notification_min_height_before_p">92dp</dimen> <!-- Height of a large notification in the status bar --> - <dimen name="notification_max_height">292dp</dimen> + <dimen name="notification_max_height">294dp</dimen> <!-- Height of an ambient notification on ambient display --> <dimen name="notification_ambient_height">400dp</dimen> @@ -102,16 +102,13 @@ <dimen name="notification_max_heads_up_height_before_p">148dp</dimen> <!-- Height of a heads up notification in the status bar --> - <dimen name="notification_max_heads_up_height">156dp</dimen> + <dimen name="notification_max_heads_up_height">162dp</dimen> <!-- Height of a heads up notification in the status bar --> <dimen name="notification_max_heads_up_height_increased">188dp</dimen> <!-- Side padding on the lockscreen on the side of notifications --> - <dimen name="notification_lockscreen_side_paddings">8dp</dimen> - - <!-- Additional side padding for custom content if the app doesn't target P yet --> - <dimen name="notification_content_custom_view_side_padding">@dimen/notification_lockscreen_side_paddings</dimen> + <dimen name="notification_side_paddings">4dp</dimen> <!-- Height of a messaging notifications with actions at least. Not that this is an upper bound and the notification won't use this much, but is measured with wrap_content --> @@ -127,7 +124,7 @@ <dimen name="notification_min_interaction_height">40dp</dimen> <!-- the padding of the shelf icon container --> - <dimen name="shelf_icon_container_padding">21dp</dimen> + <dimen name="shelf_icon_container_padding">13dp</dimen> <!-- The padding of a notification icon on top to the start of the notification. Used for custom views where the distance can't be measured --> @@ -238,7 +235,7 @@ <dimen name="qs_footer_height">48dp</dimen> <!-- The padding between the notifications and the quick settings container --> - <dimen name="qs_notification_keyguard_padding">8dp</dimen> + <dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen> <!-- Height of the status bar header bar when expanded --> <dimen name="status_bar_header_height_expanded">124dp</dimen> @@ -391,9 +388,6 @@ group. --> <dimen name="notification_children_container_divider_height">@dimen/notification_divider_height</dimen> - <!-- The height of the header for a container containing child notifications. --> - <dimen name="notification_children_container_header_height">53dp</dimen> - <!-- The top margin for the notification children container in its non-expanded form. --> <dimen name="notification_children_container_margin_top">@*android:dimen/notification_content_margin_top</dimen> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index dd31365a2c39..fed97c57ce09 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -86,10 +86,6 @@ <item type="id" name="top_roundess_animator_start_tag"/> <item type="id" name="top_roundess_animator_end_tag"/> - <item type="id" name="side_padding_animator_tag"/> - <item type="id" name="side_padding_animator_start_tag"/> - <item type="id" name="side_padding_animator_end_tag"/> - <!-- Accessibility actions for the notification menu --> <item type="id" name="action_snooze_undo"/> <item type="id" name="action_snooze_shorter"/> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index ff0357a3e2c0..e59c703afdd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -931,13 +931,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } @Override - public void setCurrentSidePaddings(float currentSidePaddings) { - super.setCurrentSidePaddings(currentSidePaddings); - mBackgroundNormal.setCurrentSidePaddings(currentSidePaddings); - mBackgroundDimmed.setCurrentSidePaddings(currentSidePaddings); - } - - @Override protected boolean childNeedsClipping(View child) { if (child instanceof NotificationBackgroundView && isClippingNeeded()) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index f53eb4897ad5..d1e6dcc9e480 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -2362,16 +2362,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView NotificationContentView contentView = (NotificationContentView) child; if (isClippingNeeded()) { return true; - } else if (!hasNoRoundingAndNoPadding() && contentView.shouldClipToSidePaddings()) { + } else if (!hasNoRounding() && contentView.shouldClipToRounding()) { return true; } } else if (child == mChildrenContainer) { - if (isClippingNeeded() || ((isGroupExpanded() || isGroupExpansionChanging()) - && getClipBottomAmount() != 0.0f && getCurrentBottomRoundness() != 0.0f)) { + if (isClippingNeeded() || !hasNoRounding()) { return true; } } else if (child instanceof NotificationGuts) { - return !hasNoRoundingAndNoPadding(); + return !hasNoRounding(); } return super.childNeedsClipping(child); } @@ -2401,9 +2400,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return super.getCustomClipPath(child); } - private boolean hasNoRoundingAndNoPadding() { - return mCurrentSidePaddings == 0 && getCurrentBottomRoundness() == 0.0f - && getCurrentTopRoundness() == 0.0f; + private boolean hasNoRounding() { + return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f; } public boolean isShowingAmbient() { @@ -2418,20 +2416,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - @Override - public void setCurrentSidePaddings(float currentSidePaddings) { - if (mIsSummaryWithChildren) { - List<ExpandableNotificationRow> notificationChildren = - mChildrenContainer.getNotificationChildren(); - int size = notificationChildren.size(); - for (int i = 0; i < size; i++) { - ExpandableNotificationRow row = notificationChildren.get(i); - row.setCurrentSidePaddings(currentSidePaddings); - } - } - super.setCurrentSidePaddings(currentSidePaddings); - } - public static class NotificationViewState extends ExpandableViewState { private final StackScrollState mOverallState; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java index db19d2f0cac9..66b3a75f4037 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java @@ -58,6 +58,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { private static final Path EMPTY_PATH = new Path(); private final Rect mOutlineRect = new Rect(); + private final Path mClipPath = new Path(); private boolean mCustomOutline; private float mOutlineAlpha = -1f; private float mOutlineRadius; @@ -69,13 +70,14 @@ public abstract class ExpandableOutlineView extends ExpandableView { private float mBottomRoundness; private float mTopRoundness; private int mBackgroundTop; - protected int mCurrentSidePaddings; /** * {@code true} if the children views of the {@link ExpandableOutlineView} are translated when * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself. */ protected boolean mShouldTranslateContents; + private boolean mClipRoundedToClipTopAmount; + private float mDistanceToTopRoundness = -1; private final ViewOutlineProvider mProvider = new ViewOutlineProvider() { @Override @@ -83,9 +85,9 @@ public abstract class ExpandableOutlineView extends ExpandableView { if (!mCustomOutline && mCurrentTopRoundness == 0.0f && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) { int translation = mShouldTranslateContents ? (int) getTranslation() : 0; - int left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings); + int left = Math.max(translation, 0); int top = mClipTopAmount + mBackgroundTop; - int right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0); + int right = getWidth() + Math.min(translation, 0); int bottom = Math.max(getActualHeight() - mClipBottomAmount, top); outline.setRect(left, top, right, bottom); } else { @@ -115,9 +117,9 @@ public abstract class ExpandableOutlineView extends ExpandableView { if (!mCustomOutline) { int translation = mShouldTranslateContents && !ignoreTranslation ? (int) getTranslation() : 0; - left = Math.max(translation + mCurrentSidePaddings, mCurrentSidePaddings); + left = Math.max(translation, 0); top = mClipTopAmount + mBackgroundTop; - right = getWidth() - mCurrentSidePaddings + Math.min(translation, 0); + right = getWidth() + Math.min(translation, 0); bottom = Math.max(getActualHeight(), top); int intersectBottom = Math.max(getActualHeight() - mClipBottomAmount, top); if (bottom != intersectBottom) { @@ -135,8 +137,6 @@ public abstract class ExpandableOutlineView extends ExpandableView { top = mOutlineRect.top; right = mOutlineRect.right; bottom = mOutlineRect.bottom; - left = Math.max(mCurrentSidePaddings, left); - right = Math.min(getWidth() - mCurrentSidePaddings, right); } height = bottom - top; if (height == 0) { @@ -162,15 +162,8 @@ public abstract class ExpandableOutlineView extends ExpandableView { return roundedRectPath; } - protected Path getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness, - float bottomRoundness) { - getRoundedRectPath(left, top, right, bottom, topRoundness, bottomRoundness, - mTmpPath); - return mTmpPath; - } - - private void getRoundedRectPath(int left, int top, int right, int bottom, float topRoundness, - float bottomRoundness, Path outPath) { + public static void getRoundedRectPath(int left, int top, int right, int bottom, + float topRoundness, float bottomRoundness, Path outPath) { outPath.reset(); int width = right - left; float topRoundnessX = topRoundness; @@ -207,20 +200,50 @@ public abstract class ExpandableOutlineView extends ExpandableView { @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { canvas.save(); + Path intersectPath = null; + if (mClipRoundedToClipTopAmount) { + int left = 0; + int top = (int) (mClipTopAmount - mDistanceToTopRoundness); + int right = getWidth(); + int bottom = (int) Math.max(getActualHeight() - mClipBottomAmount, + top + mOutlineRadius); + ExpandableOutlineView.getRoundedRectPath(left, top, right, bottom, mOutlineRadius, + 0.0f, + mClipPath); + intersectPath = mClipPath; + } + boolean clipped = false; if (childNeedsClipping(child)) { Path clipPath = getCustomClipPath(child); if (clipPath == null) { clipPath = getClipPath(); } if (clipPath != null) { + if (intersectPath != null) { + clipPath.op(intersectPath, Path.Op.INTERSECT); + } canvas.clipPath(clipPath); + clipped = true; } } + if (!clipped && intersectPath != null) { + canvas.clipPath(intersectPath); + } boolean result = super.drawChild(canvas, child, drawingTime); canvas.restore(); return result; } + @Override + public void setDistanceToTopRoundness(float distanceToTopRoundness) { + super.setDistanceToTopRoundness(distanceToTopRoundness); + if (distanceToTopRoundness != mDistanceToTopRoundness) { + mClipRoundedToClipTopAmount = distanceToTopRoundness >= 0; + mDistanceToTopRoundness = distanceToTopRoundness; + invalidate(); + } + } + protected boolean childNeedsClipping(View child) { return false; } @@ -395,10 +418,4 @@ public abstract class ExpandableOutlineView extends ExpandableView { public Path getCustomClipPath(View child) { return null; } - - public void setCurrentSidePaddings(float currentSidePaddings) { - mCurrentSidePaddings = (int) currentSidePaddings; - invalidateOutline(); - invalidate(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index f762513d2947..eafa825dd89d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -130,6 +130,14 @@ public abstract class ExpandableView extends FrameLayout { } } + /** + * Set the distance to the top roundness, from where we should start clipping a value above + * or equal to 0 is the effective distance, and if a value below 0 is received, there should + * be no clipping. + */ + public void setDistanceToTopRoundness(float distanceToTopRoundness) { + } + public void setActualHeight(int actualHeight) { setActualHeight(actualHeight, true /* notifyListeners */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java index 68cf51c04d4b..45b35d014e70 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java @@ -41,7 +41,6 @@ public class NotificationBackgroundView extends View { private int mClipBottomAmount; private int mTintColor; private float[] mCornerRadii = new float[8]; - private int mCurrentSidePaddings; private boolean mBottomIsRounded; private int mBackgroundTop; private boolean mBottomAmountClips = true; @@ -68,8 +67,7 @@ public class NotificationBackgroundView extends View { if (mBottomIsRounded && mBottomAmountClips) { bottom -= mClipBottomAmount; } - drawable.setBounds(mCurrentSidePaddings, mBackgroundTop, - getWidth() - mCurrentSidePaddings, bottom); + drawable.setBounds(0, mBackgroundTop, getWidth(), bottom); drawable.draw(canvas); } } @@ -206,11 +204,6 @@ public class NotificationBackgroundView extends View { } } - public void setCurrentSidePaddings(float currentSidePaddings) { - mCurrentSidePaddings = (int) currentSidePaddings; - invalidate(); - } - public void setBackgroundTop(int backgroundTop) { mBackgroundTop = backgroundTop; invalidate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 39c21313d378..c73e548eaa17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -136,7 +136,6 @@ public class NotificationContentView extends FrameLayout { private int mClipBottomAmount; private boolean mIsLowPriority; private boolean mIsContentExpandable; - private int mCustomViewSidePaddings; public NotificationContentView(Context context, AttributeSet attrs) { @@ -150,8 +149,6 @@ public class NotificationContentView extends FrameLayout { R.dimen.min_notification_layout_height); mNotificationContentMarginEnd = getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_content_margin_end); - mCustomViewSidePaddings = getResources().getDimensionPixelSize( - R.dimen.notification_content_custom_view_side_padding); } public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight, @@ -391,22 +388,6 @@ public class NotificationContentView extends FrameLayout { mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); - updateMargins(child); - } - - private void updateMargins(View child) { - if (child == null) { - return; - } - NotificationViewWrapper wrapper = getWrapperForView(child); - boolean isCustomView = wrapper instanceof NotificationCustomViewWrapper; - boolean needsMargins = isCustomView && - child.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P; - int padding = needsMargins ? mCustomViewSidePaddings : 0; - MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams(); - layoutParams.setMarginStart(padding); - layoutParams.setMarginEnd(padding); - child.setLayoutParams(layoutParams); } private NotificationViewWrapper getWrapperForView(View child) { @@ -456,7 +437,6 @@ public class NotificationContentView extends FrameLayout { mExpandedChild = child; mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); - updateMargins(child); } public void setHeadsUpChild(View child) { @@ -490,7 +470,6 @@ public class NotificationContentView extends FrameLayout { mHeadsUpChild = child; mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); - updateMargins(child); } public void setAmbientChild(View child) { @@ -1510,19 +1489,19 @@ public class NotificationContentView extends FrameLayout { return false; } - public boolean shouldClipToSidePaddings() { - boolean needsPaddings = shouldClipToSidePaddings(getVisibleType()); + public boolean shouldClipToRounding() { + boolean needsPaddings = shouldClipToRounding(getVisibleType()); if (mUserExpanding) { - needsPaddings |= shouldClipToSidePaddings(mTransformationStartVisibleType); + needsPaddings |= shouldClipToRounding(mTransformationStartVisibleType); } return needsPaddings; } - private boolean shouldClipToSidePaddings(int visibleType) { + private boolean shouldClipToRounding(int visibleType) { NotificationViewWrapper visibleWrapper = getVisibleWrapper(visibleType); if (visibleWrapper == null) { return false; } - return visibleWrapper.shouldClipToSidePaddings(); + return visibleWrapper.shouldClipToRounding(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java index 43018174de44..112707552e6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java @@ -128,6 +128,7 @@ public class NotificationHeaderUtil { mComparators.add(HeaderProcessor.forTextView(mRow, com.android.internal.R.id.header_text)); mDividers.add(com.android.internal.R.id.header_text_divider); + mDividers.add(com.android.internal.R.id.header_text_secondary_divider); mDividers.add(com.android.internal.R.id.time_divider); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java index b2604fe07a59..037eeb2d298b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java @@ -176,8 +176,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl final Resources res = mContext.getResources(); mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size); mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height); - mSidePadding = res.getDimensionPixelSize(R.dimen.notification_lockscreen_side_paddings); - mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding); mMenuItems.clear(); // Construct the menu items based on the notification if (mParent != null && mParent.getStatusBarNotification() != null) { @@ -498,8 +496,8 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl final int count = mMenuContainer.getChildCount(); for (int i = 0; i < count; i++) { final View v = mMenuContainer.getChildAt(i); - final float left = mSidePadding + i * mHorizSpaceForIcon; - final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1)) - mSidePadding; + final float left = i * mHorizSpaceForIcon; + final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1)); v.setX(showOnLeft ? left : right); } mOnLeft = showOnLeft; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java index 66682e4c54f2..0d2209569093 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java @@ -38,7 +38,6 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { private final Paint mGreyPaint = new Paint(); private boolean mIsLegacy; private int mLegacyColor; - private boolean mBeforeP; protected NotificationCustomViewWrapper(Context ctx, View view, ExpandableNotificationRow row) { super(ctx, view, row); @@ -119,15 +118,7 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { } @Override - public boolean shouldClipToSidePaddings() { - // Before P we ensure that they are now drawing inside out content bounds since we inset - // the view. If they target P, then we don't have that guarantee and we need to be safe. - return !mBeforeP; - } - - @Override - public void onContentUpdated(ExpandableNotificationRow row) { - super.onContentUpdated(row); - mBeforeP = row.getEntry().targetSdk < Build.VERSION_CODES.P; + public boolean shouldClipToRounding() { + return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java index 060e6d653402..d7c08cc89c25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java @@ -62,7 +62,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi } @Override - public boolean shouldClipToSidePaddings() { + public boolean shouldClipToRounding() { return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index e07112f983e7..fd085d9c2391 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -265,11 +265,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp updateActionOffset(); } - @Override - public boolean shouldClipToSidePaddings() { - return mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE; - } - private void updateActionOffset() { if (mActionsContainer != null) { // We should never push the actions higher than they are in the headsup view. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index 8a767bb718b0..c71d604c9122 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java @@ -195,7 +195,7 @@ public abstract class NotificationViewWrapper implements TransformableView { return 0; } - public boolean shouldClipToSidePaddings() { + public boolean shouldClipToRounding() { return false; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index f0bd1f94ec3d..32675d3b2aac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -309,7 +309,7 @@ public class NotificationPanelView extends PanelView implements mIndicationBottomPadding = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_bottom_padding); mQsNotificationTopPadding = getResources().getDimensionPixelSize( - R.dimen.qs_notification_keyguard_padding); + R.dimen.qs_notification_padding); } public void updateResources() { @@ -451,7 +451,8 @@ public class NotificationPanelView extends PanelView implements boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); int stackScrollerPadding; if (mStatusBarState != StatusBarState.KEYGUARD) { - stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight; + stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight + + mQsNotificationTopPadding; mTopPaddingAdjustment = 0; } else { mClockPositionAlgorithm.setup( @@ -1381,7 +1382,7 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.getIntrinsicPadding(), mQsMaxExpansionHeight + mQsNotificationTopPadding); } else { - return mQsExpansionHeight; + return mQsExpansionHeight + mQsNotificationTopPadding; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java index c0241e36941f..55050995d5f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java @@ -128,12 +128,11 @@ public class NotificationChildrenContainer extends ViewGroup { mDividerHeight = res.getDimensionPixelSize( R.dimen.notification_children_container_divider_height); mDividerAlpha = res.getFloat(R.dimen.notification_divider_alpha); - mHeaderHeight = res.getDimensionPixelSize( - R.dimen.notification_children_container_header_height); mNotificationHeaderMargin = res.getDimensionPixelSize( R.dimen.notification_children_container_margin_top); mNotificatonTopPadding = res.getDimensionPixelSize( R.dimen.notification_children_container_top_padding); + mHeaderHeight = mNotificationHeaderMargin + mNotificatonTopPadding; mCollapsedBottompadding = res.getDimensionPixelSize( com.android.internal.R.dimen.notification_content_margin_bottom); mEnableShadowOnChildNotifications = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 369e7ffa991c..167508afaa1c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -76,7 +76,6 @@ import com.android.systemui.statusbar.ActivatableNotificationView; import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.ExpandableNotificationRow; -import com.android.systemui.statusbar.ExpandableOutlineView; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationGuts; @@ -86,10 +85,8 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationSnooze; import com.android.systemui.statusbar.StackScrollerDecorView; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationUtils; -import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; @@ -126,16 +123,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}. */ - private static final int INVALID_POINTER = -1; - private static final AnimatableProperty SIDE_PADDINGS = AnimatableProperty.from( - "sidePaddings", - NotificationStackScrollLayout::setCurrentSidePadding, - NotificationStackScrollLayout::getCurrentSidePadding, - R.id.side_padding_animator_tag, - R.id.side_padding_animator_end_tag, - R.id.side_padding_animator_start_tag); - private static final AnimationProperties SIDE_PADDING_PROPERTIES = - new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + private static final int INVALID_POINTER = -1;; private ExpandHelper mExpandHelper; private NotificationSwipeHelper mSwipeHelper; @@ -143,7 +131,6 @@ public class NotificationStackScrollLayout extends ViewGroup private int mCurrentStackHeight = Integer.MAX_VALUE; private final Paint mBackgroundPaint = new Paint(); private final Path mBackgroundPath = new Path(); - private final float[] mBackgroundRadii = new float[8]; private final boolean mShouldDrawNotificationBackground; private float mExpandedHeight; @@ -174,7 +161,6 @@ public class NotificationStackScrollLayout extends ViewGroup private int mTopPadding; private int mBottomMargin; private int mBottomInset = 0; - private float mCurrentSidePadding; /** * The algorithm which calculates the properties for our children @@ -402,7 +388,6 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mHeadsUpGoingAwayAnimationsAllowed = true; private Runnable mAnimateScroll = this::animateScroll; private int mCornerRadius; - private int mLockscreenSidePaddings; private int mSidePaddings; public NotificationStackScrollLayout(Context context) { @@ -440,8 +425,7 @@ public class NotificationStackScrollLayout extends ViewGroup res.getBoolean(R.bool.config_fadeNotificationsOnDismiss); updateWillNotDraw(); - mBackgroundPaint.setAntiAlias(true); - mBackgroundPaint.setStyle(Paint.Style.FILL); + mBackgroundPaint.setAntiAlias(true);; if (DEBUG) { mDebugPaint = new Paint(); mDebugPaint.setColor(0xffff0000); @@ -490,7 +474,8 @@ public class NotificationStackScrollLayout extends ViewGroup protected void onDraw(Canvas canvas) { if (mShouldDrawNotificationBackground && !mAmbientState.isDark() && mCurrentBounds.top < mCurrentBounds.bottom) { - canvas.drawPath(mBackgroundPath, mBackgroundPaint); + canvas.drawRoundRect(mSidePaddings, mCurrentBounds.top, getWidth() - mSidePaddings, + mCurrentBounds.bottom, mCornerRadius, mCornerRadius, mBackgroundPaint); } if (DEBUG) { @@ -543,8 +528,7 @@ public class NotificationStackScrollLayout extends ViewGroup R.dimen.min_top_overscroll_to_qs); mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height); mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom); - mLockscreenSidePaddings = res.getDimensionPixelSize( - R.dimen.notification_lockscreen_side_paddings); + mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings); mMinInteractionHeight = res.getDimensionPixelSize( R.dimen.notification_min_interaction_height); mCornerRadius = res.getDimensionPixelSize( @@ -575,11 +559,15 @@ public class NotificationStackScrollLayout extends ViewGroup @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.getSize(widthMeasureSpec); + int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2, + MeasureSpec.getMode(widthMeasureSpec)); // We need to measure all children even the GONE ones, such that the heights are calculated // correctly as they are used to calculate how many we can fit on the screen. final int size = getChildCount(); for (int i = 0; i < size; i++) { - measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); + measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec); } } @@ -675,11 +663,32 @@ public class NotificationStackScrollLayout extends ViewGroup private void onPreDrawDuringAnimation() { mShelf.updateAppearance(); + updateClippingToTopRoundedCorner(); if (!mNeedsAnimation && !mChildrenUpdateRequested) { updateBackground(); } } + private void updateClippingToTopRoundedCorner() { + Float clipStart = (float) mTopPadding; + Float clipEnd = clipStart + mCornerRadius; + boolean first = true; + for (int i = 0; i < getChildCount(); i++) { + ExpandableView child = (ExpandableView) getChildAt(i); + if (child.getVisibility() == GONE) { + continue; + } + float start = child.getTranslationY(); + float end = start + Math.max(child.getActualHeight() - child.getClipBottomAmount(), + 0); + boolean clip = clipStart > start && clipStart < end + || clipEnd >= start && clipEnd <= end; + clip &= !(first && mOwnScrollY == 0); + child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0) : -1); + first = false; + } + } + private void updateScrollStateForAddedChildren() { if (mChildrenToAddAnimated.isEmpty()) { return; @@ -2255,31 +2264,9 @@ public class NotificationStackScrollLayout extends ViewGroup mScrimController.setExcludedBackgroundArea( mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null : mCurrentBounds); - updateBackgroundPath(); invalidate(); } - private void updateBackgroundPath() { - mBackgroundPath.reset(); - float topRoundness = 0; - if (mFirstVisibleBackgroundChild != null) { - topRoundness = mFirstVisibleBackgroundChild.getCurrentBackgroundRadiusTop(); - } - topRoundness = onKeyguard() ? mCornerRadius : topRoundness; - float bottomRoundNess = mCornerRadius; - mBackgroundRadii[0] = topRoundness; - mBackgroundRadii[1] = topRoundness; - mBackgroundRadii[2] = topRoundness; - mBackgroundRadii[3] = topRoundness; - mBackgroundRadii[4] = bottomRoundNess; - mBackgroundRadii[5] = bottomRoundNess; - mBackgroundRadii[6] = bottomRoundNess; - mBackgroundRadii[7] = bottomRoundNess; - mBackgroundPath.addRoundRect(mCurrentSidePadding, mCurrentBounds.top, - getWidth() - mCurrentSidePadding, mCurrentBounds.bottom, mBackgroundRadii, - Path.Direction.CCW); - } - /** * Update the background bounds to the new desired bounds */ @@ -2292,8 +2279,8 @@ public class NotificationStackScrollLayout extends ViewGroup mBackgroundBounds.left = mTempInt2[0]; mBackgroundBounds.right = mTempInt2[0] + getWidth(); } - mBackgroundBounds.left += mCurrentSidePadding; - mBackgroundBounds.right -= mCurrentSidePadding; + mBackgroundBounds.left += mSidePaddings; + mBackgroundBounds.right -= mSidePaddings; if (!mIsExpanded) { mBackgroundBounds.top = 0; mBackgroundBounds.bottom = 0; @@ -2902,8 +2889,7 @@ public class NotificationStackScrollLayout extends ViewGroup private void applyRoundedNess() { if (mFirstVisibleBackgroundChild != null) { - mFirstVisibleBackgroundChild.setTopRoundness( - mStatusBarState == StatusBarState.KEYGUARD ? 1.0f : 0.0f, + mFirstVisibleBackgroundChild.setTopRoundness(1.0f, mFirstVisibleBackgroundChild.isShown() && !mChildrenToAddAnimated.contains(mFirstVisibleBackgroundChild)); } @@ -2912,7 +2898,6 @@ public class NotificationStackScrollLayout extends ViewGroup mLastVisibleBackgroundChild.isShown() && !mChildrenToAddAnimated.contains(mLastVisibleBackgroundChild)); } - updateBackgroundPath(); invalidate(); } @@ -2922,7 +2907,6 @@ public class NotificationStackScrollLayout extends ViewGroup generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); - updateCurrentSidePaddings(child); } private void updateHideSensitiveForChild(View child) { @@ -3021,6 +3005,7 @@ public class NotificationStackScrollLayout extends ViewGroup mAnimationEvents.clear(); updateBackground(); updateViewShadows(); + updateClippingToTopRoundedCorner(); } else { applyCurrentState(); } @@ -3714,6 +3699,7 @@ public class NotificationStackScrollLayout extends ViewGroup setAnimationRunning(false); updateBackground(); updateViewShadows(); + updateClippingToTopRoundedCorner(); } private void updateViewShadows() { @@ -4382,43 +4368,6 @@ public class NotificationStackScrollLayout extends ViewGroup public void setStatusBarState(int statusBarState) { mStatusBarState = statusBarState; mAmbientState.setStatusBarState(statusBarState); - applyRoundedNess(); - updateSidePaddings(); - } - - private void updateSidePaddings() { - int sidePaddings = mStatusBarState == StatusBarState.KEYGUARD ? mLockscreenSidePaddings : 0; - if (sidePaddings != mSidePaddings) { - boolean animate = isShown(); - mSidePaddings = sidePaddings; - PropertyAnimator.setProperty(this, SIDE_PADDINGS, sidePaddings, - SIDE_PADDING_PROPERTIES, animate); - } - } - - protected void setCurrentSidePadding(float sidePadding) { - mCurrentSidePadding = sidePadding; - updateBackground(); - applySidePaddingsToChildren(); - } - - private void applySidePaddingsToChildren() { - for (int i = 0; i < getChildCount(); i++) { - View view = getChildAt(i); - updateCurrentSidePaddings(view); - } - } - - private void updateCurrentSidePaddings(View view) { - if (!(view instanceof ExpandableOutlineView)) { - return; - } - ExpandableOutlineView outlineView = (ExpandableOutlineView) view; - outlineView.setCurrentSidePaddings(mCurrentSidePadding); - } - - protected float getCurrentSidePadding() { - return mCurrentSidePadding; } public void setExpandingVelocity(float expandingVelocity) { diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index a024d5a8e3ff..86063c3d3bbd 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1162,12 +1162,12 @@ class AlarmManagerService extends SystemService { // ignored; both services live in system_server } publishBinderService(Context.ALARM_SERVICE, mService); - mForceAppStandbyTracker.start(); } @Override public void onBootPhase(int phase) { if (phase == PHASE_SYSTEM_SERVICES_READY) { + mForceAppStandbyTracker.start(); mConstants.start(getContext().getContentResolver()); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mLocalDeviceIdleController diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 04d292fa1ae4..dcb0fabf0345 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -293,10 +293,13 @@ public final class BatteryService extends SystemService { private void updateBatteryWarningLevelLocked() { final ContentResolver resolver = mContext.getContentResolver(); - int defWarnLevel = mContext.getResources().getInteger( + final int defWarnLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_lowBatteryWarningLevel); - mLowBatteryWarningLevel = Settings.Global.getInt(resolver, + final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); + + mLowBatteryWarningLevel = Math.min(defWarnLevel, lowPowerModeTriggerLevel); + if (mLowBatteryWarningLevel == 0) { mLowBatteryWarningLevel = defWarnLevel; } diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java index 61d3833d3197..8776f3a9f6c8 100644 --- a/services/core/java/com/android/server/ForceAppStandbyTracker.java +++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java @@ -25,6 +25,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -33,8 +34,10 @@ import android.os.PowerManagerInternal; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.provider.Settings; import android.util.ArraySet; import android.util.Pair; +import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; @@ -59,15 +62,16 @@ import java.util.List; * - Global "force all apps standby" mode enforced by battery saver. * * TODO: In general, we can reduce the number of callbacks by checking all signals before sending - * each callback. For example, even when an UID comes into the foreground, if it wasn't - * originally restricted, then there's no need to send an event. - * Doing this would be error-prone, so we punt it for now, but we should revisit it later. + * each callback. For example, even when an UID comes into the foreground, if it wasn't + * originally restricted, then there's no need to send an event. + * Doing this would be error-prone, so we punt it for now, but we should revisit it later. * * Test: - atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java + * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java */ public class ForceAppStandbyTracker { private static final String TAG = "ForceAppStandbyTracker"; + private static final boolean DEBUG = false; @GuardedBy("ForceAppStandbyTracker.class") private static ForceAppStandbyTracker sInstance; @@ -107,7 +111,43 @@ public class ForceAppStandbyTracker { boolean mStarted; @GuardedBy("mLock") - boolean mForceAllAppsStandby; + boolean mForceAllAppsStandby; // True if device is in extreme battery saver mode + + @GuardedBy("mLock") + boolean mForcedAppStandbyEnabled; // True if the forced app standby feature is enabled + + private class FeatureFlagObserver extends ContentObserver { + FeatureFlagObserver() { + super(null); + } + + void register() { + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED), + false, this); + } + + boolean isForcedAppStandbyEnabled() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1; + } + + @Override + public void onChange(boolean selfChange) { + final boolean enabled = isForcedAppStandbyEnabled(); + synchronized (mLock) { + if (mForcedAppStandbyEnabled == enabled) { + return; + } + mForcedAppStandbyEnabled = enabled; + if (DEBUG) { + Slog.d(TAG, + "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled); + } + } + mHandler.notifyFeatureFlagChanged(); + } + } public static abstract class Listener { /** @@ -246,6 +286,9 @@ public class ForceAppStandbyTracker { mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager()); mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService()); mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal()); + final FeatureFlagObserver flagObserver = new FeatureFlagObserver(); + flagObserver.register(); + mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled(); try { mIActivityManager.registerUidObserver(new UidObserver(), @@ -364,7 +407,7 @@ public class ForceAppStandbyTracker { */ boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, boolean restricted) { - final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName); + final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName); final boolean wasRestricted = index >= 0; if (wasRestricted == restricted) { return false; @@ -418,25 +461,30 @@ public class ForceAppStandbyTracker { } private final class UidObserver extends IUidObserver.Stub { - @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { + @Override + public void onUidStateChanged(int uid, int procState, long procStateSeq) { } - @Override public void onUidGone(int uid, boolean disabled) { + @Override + public void onUidGone(int uid, boolean disabled) { uidToBackground(uid, /*remove=*/ true); } - @Override public void onUidActive(int uid) { + @Override + public void onUidActive(int uid) { uidToForeground(uid); } - @Override public void onUidIdle(int uid, boolean disabled) { + @Override + public void onUidIdle(int uid, boolean disabled) { // Just to avoid excessive memcpy, don't remove from the array in this case. uidToBackground(uid, /*remove=*/ false); } - @Override public void onUidCachedChanged(int uid, boolean cached) { + @Override + public void onUidCachedChanged(int uid, boolean cached) { } - }; + } private final class AppOpsWatcher extends IAppOpsCallback.Stub { @Override @@ -481,8 +529,8 @@ public class ForceAppStandbyTracker { private static final int MSG_ALL_WHITELIST_CHANGED = 4; private static final int MSG_TEMP_WHITELIST_CHANGED = 5; private static final int MSG_FORCE_ALL_CHANGED = 6; - private static final int MSG_USER_REMOVED = 7; + private static final int MSG_FEATURE_FLAG_CHANGED = 8; public MyHandler(Looper looper) { super(looper); @@ -491,6 +539,7 @@ public class ForceAppStandbyTracker { public void notifyUidForegroundStateChanged(int uid) { obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget(); } + public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) { obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget(); } @@ -511,12 +560,16 @@ public class ForceAppStandbyTracker { obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget(); } + public void notifyFeatureFlagChanged() { + obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget(); + } + public void doUserRemoved(int userId) { obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget(); } @Override - public void dispatchMessage(Message msg) { + public void handleMessage(Message msg) { switch (msg.what) { case MSG_USER_REMOVED: handleUserRemoved(msg.arg1); @@ -562,6 +615,19 @@ public class ForceAppStandbyTracker { l.onForceAllAppsStandbyChanged(sender); } return; + case MSG_FEATURE_FLAG_CHANGED: + // Feature flag for forced app standby changed. + final boolean unblockAlarms; + synchronized (mLock) { + unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby; + } + for (Listener l: cloneListeners()) { + l.updateAllJobs(); + if (unblockAlarms) { + l.unblockAllUnrestrictedAlarms(); + } + } + return; case MSG_USER_REMOVED: handleUserRemoved(msg.arg1); return; @@ -701,7 +767,7 @@ public class ForceAppStandbyTracker { return true; } - return isRunAnyRestrictedLocked(uid, packageName); + return mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName); } } @@ -766,6 +832,9 @@ public class ForceAppStandbyTracker { public void dump(PrintWriter pw, String indent) { synchronized (mLock) { pw.print(indent); + pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled); + + pw.print(indent); pw.print("Force all apps standby: "); pw.println(isForceAllAppsStandbyEnabled()); diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 17adb1a74e30..2224913b2cf6 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -30,6 +30,7 @@ import android.net.RouteInfo; import android.net.ip.InterfaceController; import android.net.ip.RouterAdvertisementDaemon; import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.net.util.InterfaceParams; import android.net.util.NetdService; import android.net.util.SharedLog; import android.os.INetworkManagementService; @@ -48,7 +49,6 @@ import com.android.internal.util.StateMachine; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; @@ -120,8 +120,7 @@ public class TetherInterfaceStateMachine extends StateMachine { private int mLastError; private int mServingMode; private String mMyUpstreamIfaceName; // may change over time - private NetworkInterface mNetworkInterface; - private byte[] mHwAddr; + private InterfaceParams mInterfaceParams; // TODO: De-duplicate this with mLinkProperties above. Currently, these link // properties are those selected by the IPv6TetheringCoordinator and relayed // to us. By comparison, mLinkProperties contains the addresses and directly @@ -247,31 +246,16 @@ public class TetherInterfaceStateMachine extends StateMachine { } private boolean startIPv6() { - // TODO: Refactor for testability (perhaps passing an android.system.Os - // instance and calling getifaddrs() directly). - try { - mNetworkInterface = NetworkInterface.getByName(mIfaceName); - } catch (SocketException e) { - mLog.e("Error looking up NetworkInterfaces: " + e); - stopIPv6(); - return false; - } - if (mNetworkInterface == null) { - mLog.e("Failed to find NetworkInterface"); - stopIPv6(); - return false; - } - - try { - mHwAddr = mNetworkInterface.getHardwareAddress(); - } catch (SocketException e) { - mLog.e("Failed to find hardware address: " + e); + // TODO: Refactor for better testability. This is one of the things + // that prohibits unittesting IPv6 tethering setup. + mInterfaceParams = InterfaceParams.getByName(mIfaceName); + if (mInterfaceParams == null) { + mLog.e("Failed to find InterfaceParams"); stopIPv6(); return false; } - final int ifindex = mNetworkInterface.getIndex(); - mRaDaemon = new RouterAdvertisementDaemon(mIfaceName, ifindex, mHwAddr); + mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams); if (!mRaDaemon.start()) { stopIPv6(); return false; @@ -281,8 +265,7 @@ public class TetherInterfaceStateMachine extends StateMachine { } private void stopIPv6() { - mNetworkInterface = null; - mHwAddr = null; + mInterfaceParams = null; setRaParams(null); if (mRaDaemon != null) { diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index a30e06399614..fd9ffb223174 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -278,7 +278,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { // VisibleForTesting public static String[] getExtraPeople(Bundle extras) { - Object people = extras.get(Notification.EXTRA_PEOPLE); + Object people = extras.get(Notification.EXTRA_PEOPLE_LIST); if (people instanceof String[]) { return (String[]) people; } @@ -305,6 +305,16 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return array; } + if (arrayList.get(0) instanceof Notification.Person) { + ArrayList<Notification.Person> list = (ArrayList<Notification.Person>) arrayList; + final int N = list.size(); + String[] array = new String[N]; + for (int i = 0; i < N; i++) { + array[i] = list.get(i).resolveToLegacyUri(); + } + return array; + } + return null; } @@ -459,7 +469,9 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { lookupResult = searchContacts(mContext, uri); } else { lookupResult = new LookupResult(); // invalid person for the cache - Slog.w(TAG, "unsupported URI " + handle); + if (!"name".equals(uri.getScheme())) { + Slog.w(TAG, "unsupported URI " + handle); + } } if (lookupResult != null) { synchronized (mPeopleCache) { diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 31a1abb39461..7d9736ed3fe5 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -38,6 +38,7 @@ import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.PacketSocketAddress; @@ -56,7 +57,6 @@ import java.lang.Thread; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -247,7 +247,7 @@ public class ApfFilter { private final ApfCapabilities mApfCapabilities; private final IpClient.Callback mIpClientCallback; - private final NetworkInterface mNetworkInterface; + private final InterfaceParams mInterfaceParams; private final IpConnectivityLog mMetricsLog; @VisibleForTesting @@ -269,11 +269,11 @@ public class ApfFilter { private int mIPv4PrefixLength; @VisibleForTesting - ApfFilter(ApfConfiguration config, NetworkInterface networkInterface, + ApfFilter(ApfConfiguration config, InterfaceParams ifParams, IpClient.Callback ipClientCallback, IpConnectivityLog log) { mApfCapabilities = config.apfCapabilities; mIpClientCallback = ipClientCallback; - mNetworkInterface = networkInterface; + mInterfaceParams = ifParams; mMulticastFilter = config.multicastFilter; mDrop802_3Frames = config.ieee802_3Filter; @@ -287,7 +287,7 @@ public class ApfFilter { } private void log(String s) { - Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s); + Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); } @GuardedBy("this") @@ -332,14 +332,14 @@ public class ApfFilter { void maybeStartFilter() { FileDescriptor socket; try { - mHardwareAddress = mNetworkInterface.getHardwareAddress(); + mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); synchronized(this) { // Install basic filters installNewProgramLocked(); } socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, - mNetworkInterface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress( + (short) ETH_P_IPV6, mInterfaceParams.index); Os.bind(socket, addr); NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); } catch(SocketException|ErrnoException e) { @@ -1168,10 +1168,10 @@ public class ApfFilter { * filtering using APF programs. */ public static ApfFilter maybeCreate(ApfConfiguration config, - NetworkInterface networkInterface, IpClient.Callback ipClientCallback) { - if (config == null) return null; + InterfaceParams ifParams, IpClient.Callback ipClientCallback) { + if (config == null || ifParams == null) return null; ApfCapabilities apfCapabilities = config.apfCapabilities; - if (apfCapabilities == null || networkInterface == null) return null; + if (apfCapabilities == null) return null; if (apfCapabilities.apfVersionSupported == 0) return null; if (apfCapabilities.maximumApfProgramSize < 512) { Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); @@ -1186,7 +1186,7 @@ public class ApfFilter { Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); return null; } - return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog()); + return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog()); } public synchronized void shutdown() { diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index ed78175bd395..9056312da681 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -34,6 +34,7 @@ import android.net.TrafficStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpErrorEvent; +import android.net.util.InterfaceParams; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,7 +51,6 @@ import java.io.FileDescriptor; import java.io.IOException; import java.lang.Thread; import java.net.Inet4Address; -import java.net.NetworkInterface; import java.net.SocketException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -187,7 +187,8 @@ public class DhcpClient extends StateMachine { private final String mIfaceName; private boolean mRegisteredForPreDhcpNotification; - private NetworkInterface mIface; + private InterfaceParams mIface; + // TODO: MacAddress-ify more of this class hierarchy. private byte[] mHwAddr; private PacketSocketAddress mInterfaceBroadcastAddr; private int mTransactionId; @@ -221,6 +222,7 @@ public class DhcpClient extends StateMachine { return new WakeupMessage(mContext, getHandler(), cmdName, cmd); } + // TODO: Take an InterfaceParams instance instead of an interface name String. private DhcpClient(Context context, StateMachine controller, String iface) { super(TAG); @@ -262,23 +264,23 @@ public class DhcpClient extends StateMachine { } public static DhcpClient makeDhcpClient( - Context context, StateMachine controller, String intf) { - DhcpClient client = new DhcpClient(context, controller, intf); + Context context, StateMachine controller, InterfaceParams ifParams) { + DhcpClient client = new DhcpClient(context, controller, ifParams.name); + client.mIface = ifParams; client.start(); return client; } private boolean initInterface() { - try { - mIface = NetworkInterface.getByName(mIfaceName); - mHwAddr = mIface.getHardwareAddress(); - mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(), - DhcpPacket.ETHER_BROADCAST); - return true; - } catch(SocketException | NullPointerException e) { - Log.e(TAG, "Can't determine ifindex or MAC address for " + mIfaceName, e); + if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName); + if (mIface == null) { + Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName); return false; } + + mHwAddr = mIface.macAddr.toByteArray(); + mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST); + return true; } private void startNewTransaction() { @@ -293,7 +295,7 @@ public class DhcpClient extends StateMachine { private boolean initPacketSocket() { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.index); Os.bind(mPacketSock, addr); NetworkUtils.attachDhcpFilter(mPacketSock); } catch(SocketException|ErrnoException e) { diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java index 6cf4fa9a3dfc..e6ddbbc95469 100644 --- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java +++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java @@ -21,6 +21,7 @@ import static android.system.OsConstants.*; import android.net.NetworkUtils; import android.net.util.PacketReader; import android.net.util.ConnectivityPacketSummary; +import android.net.util.InterfaceParams; import android.os.Handler; import android.system.ErrnoException; import android.system.Os; @@ -35,7 +36,6 @@ import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.io.IOException; -import java.net.NetworkInterface; import java.net.SocketException; @@ -69,24 +69,12 @@ public class ConnectivityPacketTracker { private boolean mRunning; private String mDisplayName; - public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) { - final String ifname; - final int ifindex; - final byte[] hwaddr; - final int mtu; - - try { - ifname = netif.getName(); - ifindex = netif.getIndex(); - hwaddr = netif.getHardwareAddress(); - mtu = netif.getMTU(); - } catch (NullPointerException|SocketException e) { - throw new IllegalArgumentException("bad network interface", e); - } + public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) { + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); - mTag = TAG + "." + ifname; + mTag = TAG + "." + ifParams.name; mLog = log; - mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu); + mPacketListener = new PacketListener(h, ifParams); } public void start(String displayName) { @@ -102,13 +90,11 @@ public class ConnectivityPacketTracker { } private final class PacketListener extends PacketReader { - private final int mIfIndex; - private final byte mHwAddr[]; + private final InterfaceParams mInterface; - PacketListener(Handler h, int ifindex, byte[] hwaddr, int mtu) { - super(h, mtu); - mIfIndex = ifindex; - mHwAddr = hwaddr; + PacketListener(Handler h, InterfaceParams ifParams) { + super(h, ifParams.defaultMtu); + mInterface = ifParams; } @Override @@ -117,7 +103,7 @@ public class ConnectivityPacketTracker { try { s = Os.socket(AF_PACKET, SOCK_RAW, 0); NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER); - Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex)); + Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index)); } catch (ErrnoException | IOException e) { logError("Failed to create packet tracking socket: ", e); closeFd(s); @@ -129,7 +115,7 @@ public class ConnectivityPacketTracker { @Override protected void handlePacket(byte[] recvbuf, int length) { final String summary = ConnectivityPacketSummary.summarize( - mHwAddr, recvbuf, length); + mInterface.macAddr, recvbuf, length); if (summary == null) return; if (DBG) Log.d(mTag, summary); diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index fdb366c55a7b..d3a97b3851f4 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -35,6 +35,7 @@ import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.net.util.NetworkConstants; @@ -63,7 +64,6 @@ import java.io.PrintWriter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; @@ -556,7 +556,7 @@ public class IpClient extends StateMachine { private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final InterfaceController mInterfaceCtrl; - private NetworkInterface mNetworkInterface; + private InterfaceParams mInterfaceParams; /** * Non-final member variables accessed only from within our StateMachine. @@ -722,7 +722,12 @@ public class IpClient extends StateMachine { return; } - getNetworkInterface(); + mInterfaceParams = InterfaceParams.getByName(mInterfaceName); + if (mInterfaceParams == null) { + logError("Failed to find InterfaceParams for " + mInterfaceName); + // TODO: call doImmediateProvisioningFailure() with an error code + // indicating something like "interface not ready". + } mCallback.setNeighborDiscoveryOffload(true); sendMessage(CMD_START, new ProvisioningConfiguration(req)); @@ -858,7 +863,7 @@ public class IpClient extends StateMachine { protected String getLogRecString(Message msg) { final String logLine = String.format( "%s/%d %d %d %s [%s]", - mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(), + mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index, msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger); final String richerLogLine = getWhatToString(msg.what) + " " + logLine; @@ -889,15 +894,6 @@ public class IpClient extends StateMachine { mLog.log(msg); } - private void getNetworkInterface() { - try { - mNetworkInterface = NetworkInterface.getByName(mInterfaceName); - } catch (SocketException | NullPointerException e) { - // TODO: throw new IllegalStateException. - logError("Failed to get interface object: %s", e); - } - } - // This needs to be called with care to ensure that our LinkProperties // are in sync with the actual LinkProperties of the interface. For example, // we should only call this if we know for sure that there are no IP addresses @@ -1218,7 +1214,7 @@ public class IpClient extends StateMachine { } } else { // Start DHCPv4. - mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceName); + mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams); mDhcpClient.registerForPreDhcpNotification(); mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP); } @@ -1245,7 +1241,7 @@ public class IpClient extends StateMachine { try { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, - mInterfaceName, + mInterfaceParams, getHandler(), mLog, new IpReachabilityMonitor.Callback() { @@ -1447,7 +1443,7 @@ public class IpClient extends StateMachine { mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); apfConfig.ethTypeBlackList = mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList); - mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback); + mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. if (mApfFilter == null) { @@ -1515,7 +1511,7 @@ public class IpClient extends StateMachine { private ConnectivityPacketTracker createPacketTracker() { try { return new ConnectivityPacketTracker( - getHandler(), mNetworkInterface, mConnectivityPacketLog); + getHandler(), mInterfaceParams, mConnectivityPacketLog); } catch (IllegalArgumentException e) { return null; } diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java index 680733478657..fc07aa1ecd17 100644 --- a/services/net/java/android/net/ip/IpNeighborMonitor.java +++ b/services/net/java/android/net/ip/IpNeighborMonitor.java @@ -16,7 +16,11 @@ package android.net.ip; -import android.net.netlink.NetlinkConstants; +import static android.net.netlink.NetlinkConstants.hexify; +import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; +import static android.net.netlink.NetlinkConstants.stringForNlMsgType; + +import android.net.MacAddress; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; @@ -92,37 +96,35 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex; final InetAddress ip; final short nudState; - final byte[] linkLayerAddr; + final MacAddress macAddr; public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, - short nudState, byte[] linkLayerAddr) { + short nudState, MacAddress macAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; this.ip = ip; this.nudState = nudState; - this.linkLayerAddr = linkLayerAddr; + this.macAddr = macAddr; } boolean isConnected() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateConnected(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } boolean isValid() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateValid(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } @Override public String toString() { final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); return j.add("@" + elapsedMs) - .add(NetlinkConstants.stringForNlMsgType(msgType)) + .add(stringForNlMsgType(msgType)) .add("if=" + ifindex) .add(ip.getHostAddress()) .add(StructNdMsg.stringForNudState(nudState)) - .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]") + .add("[" + macAddr + "]") .toString(); } } @@ -183,7 +185,7 @@ public class IpNeighborMonitor extends PacketReader { final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); if (nlMsg == null || nlMsg.getHeader() == null) { byteBuffer.position(position); - mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer)); + mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); break; } @@ -217,12 +219,13 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex = ndMsg.ndm_ifindex; final InetAddress destination = neighMsg.getDestination(); final short nudState = - (msgType == NetlinkConstants.RTM_DELNEIGH) + (msgType == RTM_DELNEIGH) ? StructNdMsg.NUD_NONE : ndMsg.ndm_state; final NeighborEvent event = new NeighborEvent( - whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress()); + whenMs, msgType, ifindex, destination, nudState, + getMacAddress(neighMsg.getLinkLayerAddress())); if (VDBG) { Log.d(TAG, neighMsg.toString()); @@ -233,4 +236,16 @@ public class IpNeighborMonitor extends PacketReader { mConsumer.accept(event); } + + private static MacAddress getMacAddress(byte[] linkLayerAddress) { + if (linkLayerAddress != null) { + try { + return MacAddress.fromBytes(linkLayerAddress); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); + } + } + + return null; + } } diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index b31ffbba0279..7e02a2881da8 100644 --- a/services/net/java/android/net/ip/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -26,6 +26,7 @@ import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpReachabilityEvent; import android.net.netlink.StructNdMsg; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.SharedLog; import android.os.Handler; @@ -46,9 +47,7 @@ import java.io.PrintWriter; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.NetworkInterface; import java.net.SocketAddress; -import java.net.SocketException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -168,8 +167,7 @@ public class IpReachabilityMonitor { } } - private final String mInterfaceName; - private final int mInterfaceIndex; + private final InterfaceParams mInterfaceParams; private final IpNeighborMonitor mIpNeighborMonitor; private final SharedLog mLog; private final Callback mCallback; @@ -182,30 +180,25 @@ public class IpReachabilityMonitor { private volatile long mLastProbeTimeMs; public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback) { - this(context, ifName, h, log, callback, null); - } - - public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback, + Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker) { - this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker, - Dependencies.makeDefault(context, ifName)); + this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name)); } @VisibleForTesting - IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback, + IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker, Dependencies dependencies) { - mInterfaceName = ifName; + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); + + mInterfaceParams = ifParams; mLog = log.forSubComponent(TAG); mCallback = callback; mMultinetworkPolicyTracker = tracker; - mInterfaceIndex = ifIndex; mDependencies = dependencies; mIpNeighborMonitor = new IpNeighborMonitor(h, mLog, (NeighborEvent event) -> { - if (mInterfaceIndex != event.ifindex) return; + if (mInterfaceParams.index != event.ifindex) return; if (!mNeighborWatchList.containsKey(event.ip)) return; final NeighborEvent prev = mNeighborWatchList.put(event.ip, event); @@ -241,7 +234,7 @@ public class IpReachabilityMonitor { private String describeWatchList(String sep) { final StringBuilder sb = new StringBuilder(); - sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep); + sb.append("iface{" + mInterfaceParams + "}," + sep); sb.append("ntable=[" + sep); String delimiter = ""; for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) { @@ -262,10 +255,10 @@ public class IpReachabilityMonitor { } public void updateLinkProperties(LinkProperties lp) { - if (!mInterfaceName.equals(lp.getInterfaceName())) { + if (!mInterfaceParams.name.equals(lp.getInterfaceName())) { // TODO: figure out whether / how to cope with interface changes. Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() + - "' does not match: " + mInterfaceName); + "' does not match: " + mInterfaceParams.name); return; } @@ -353,10 +346,10 @@ public class IpReachabilityMonitor { mDependencies.acquireWakeLock(getProbeWakeLockDuration()); } - for (InetAddress target : ipProbeList) { - final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target); + for (InetAddress ip : ipProbeList) { + final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip); mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)", - target.getHostAddress(), rval)); + ip.getHostAddress(), rval)); logEvent(IpReachabilityEvent.PROBE, rval); } mLastProbeTimeMs = SystemClock.elapsedRealtime(); @@ -378,22 +371,9 @@ public class IpReachabilityMonitor { return (numUnicastProbes * retransTimeMs) + gracePeriodMs; } - private static int getInterfaceIndex(String ifname) { - final NetworkInterface iface; - try { - iface = NetworkInterface.getByName(ifname); - } catch (SocketException e) { - throw new IllegalArgumentException("invalid interface '" + ifname + "': ", e); - } - if (iface == null) { - throw new IllegalArgumentException("NetworkInterface was null for " + ifname); - } - return iface.getIndex(); - } - private void logEvent(int probeType, int errorCode) { int eventType = probeType | (errorCode & 0xff); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } private void logNudFailed(ProvisioningChange delta) { @@ -401,6 +381,6 @@ public class IpReachabilityMonitor { boolean isFromProbe = (duration < getProbeWakeLockDuration()); boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING); int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } } diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java index cb3123ce466a..49a1e79fd71e 100644 --- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java +++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java @@ -25,6 +25,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.TrafficStats; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.StructGroupReq; @@ -96,9 +97,7 @@ public class RouterAdvertisementDaemon { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - private final String mIfName; - private final int mIfIndex; - private final byte[] mHwAddr; + private final InterfaceParams mInterface; private final InetSocketAddress mAllNodes; // This lock is to protect the RA from being updated while being @@ -223,11 +222,9 @@ public class RouterAdvertisementDaemon { } - public RouterAdvertisementDaemon(String ifname, int ifindex, byte[] hwaddr) { - mIfName = ifname; - mIfIndex = ifindex; - mHwAddr = hwaddr; - mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0); + public RouterAdvertisementDaemon(InterfaceParams ifParams) { + mInterface = ifParams; + mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0); mDeprecatedInfoTracker = new DeprecatedInfoTracker(); } @@ -279,7 +276,7 @@ public class RouterAdvertisementDaemon { try { putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute); - putSlla(ra, mHwAddr); + putSlla(ra, mInterface.macAddr.toByteArray()); mRaLength = ra.position(); // https://tools.ietf.org/html/rfc5175#section-4 says: @@ -579,9 +576,9 @@ public class RouterAdvertisementDaemon { // Setting SNDTIMEO is purely for defensive purposes. Os.setsockoptTimeval( mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS)); - Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName); + Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name); NetworkUtils.protectFromVpn(mSocket); - NetworkUtils.setupRaSocket(mSocket, mIfIndex); + NetworkUtils.setupRaSocket(mSocket, mInterface.index); } catch (ErrnoException | IOException e) { Log.e(TAG, "Failed to create RA daemon socket: " + e); return false; @@ -614,7 +611,7 @@ public class RouterAdvertisementDaemon { final InetAddress destip = dest.getAddress(); return (destip instanceof Inet6Address) && destip.isLinkLocalAddress() && - (((Inet6Address) destip).getScopeId() == mIfIndex); + (((Inet6Address) destip).getScopeId() == mInterface.index); } private void maybeSendRA(InetSocketAddress dest) { diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java index dae93afb6599..4951400eed84 100644 --- a/services/net/java/android/net/util/ConnectivityPacketSummary.java +++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java @@ -17,6 +17,7 @@ package android.net.util; import android.net.dhcp.DhcpPacket; +import android.net.MacAddress; import java.net.InetAddress; import java.net.UnknownHostException; @@ -45,21 +46,20 @@ public class ConnectivityPacketSummary { private final ByteBuffer mPacket; private final String mSummary; - public static String summarize(byte[] hwaddr, byte[] buffer) { + public static String summarize(MacAddress hwaddr, byte[] buffer) { return summarize(hwaddr, buffer, buffer.length); } // Methods called herein perform some but by no means all error checking. // They may throw runtime exceptions on malformed packets. - public static String summarize(byte[] hwaddr, byte[] buffer, int length) { - if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null; - if (buffer == null) return null; + public static String summarize(MacAddress macAddr, byte[] buffer, int length) { + if ((macAddr == null) || (buffer == null)) return null; length = Math.min(length, buffer.length); - return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString(); + return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString(); } - private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) { - mHwAddr = hwaddr; + private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) { + mHwAddr = macAddr.toByteArray(); mBytes = buffer; mLength = Math.min(length, mBytes.length); mPacket = ByteBuffer.wrap(mBytes, 0, mLength); diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java new file mode 100644 index 000000000000..a4b2fbb6d963 --- /dev/null +++ b/services/net/java/android/net/util/InterfaceParams.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package android.net.util; + +import static android.net.MacAddress.ALL_ZEROS_ADDRESS; +import static android.net.util.NetworkConstants.ETHER_MTU; +import static android.net.util.NetworkConstants.IPV6_MIN_MTU; +import static com.android.internal.util.Preconditions.checkArgument; + +import android.net.MacAddress; +import android.text.TextUtils; + +import java.net.NetworkInterface; +import java.net.SocketException; + + +/** + * Encapsulate the interface parameters common to IpClient/IpServer components. + * + * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient + * and IpServer (sub)components need most or all of this information at some + * point during their lifecycles, so pass only this simplified object around + * which can be created once when IpClient/IpServer are told to start. + * + * @hide + */ +public class InterfaceParams { + public final String name; + public final int index; + public final MacAddress macAddr; + public final int defaultMtu; + + public static InterfaceParams getByName(String name) { + final NetworkInterface netif = getNetworkInterfaceByName(name); + if (netif == null) return null; + + // Not all interfaces have MAC addresses, e.g. rmnet_data0. + final MacAddress macAddr = getMacAddress(netif); + + try { + return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU()); + } catch (IllegalArgumentException|SocketException e) { + return null; + } + } + + public InterfaceParams(String name, int index, MacAddress macAddr) { + this(name, index, macAddr, ETHER_MTU); + } + + public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) { + checkArgument((!TextUtils.isEmpty(name)), "impossible interface name"); + checkArgument((index > 0), "invalid interface index"); + this.name = name; + this.index = index; + this.macAddr = (macAddr != null) ? macAddr : ALL_ZEROS_ADDRESS; + this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU; + } + + @Override + public String toString() { + return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu); + } + + private static NetworkInterface getNetworkInterfaceByName(String name) { + try { + return NetworkInterface.getByName(name); + } catch (NullPointerException|SocketException e) { + return null; + } + } + + private static MacAddress getMacAddress(NetworkInterface netif) { + try { + return MacAddress.fromBytes(netif.getHardwareAddress()); + } catch (IllegalArgumentException|NullPointerException|SocketException e) { + return null; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java index 467b47acd48a..14b118ebd2e1 100644 --- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java +++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java @@ -37,6 +37,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; +import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.filters.LargeTest; import android.support.test.runner.AndroidJUnit4; @@ -50,7 +51,6 @@ import org.junit.Test; import org.junit.runner.RunWith; /** - * TODO: Also add a test for temp power whitelist * Tests that background restrictions on jobs work as expected. * This test requires test-apps/JobTestApp to be installed on the device. * To run this test from root of checkout: @@ -144,15 +144,29 @@ public class BackgroundRestrictionsTest { awaitJobStop(DEFAULT_WAIT_TIMEOUT)); } + @Test + public void testFeatureFlag() throws Exception { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.FORCED_APP_STANDBY_ENABLED, 0); + scheduleAndAssertJobStarted(); + setAppOpsModeAllowed(false); + mIActivityManager.makePackageIdle(TEST_APP_PACKAGE, UserHandle.USER_CURRENT); + assertFalse("Job stopped even when feature flag was disabled", + awaitJobStop(DEFAULT_WAIT_TIMEOUT)); + } + @After public void tearDown() throws Exception { - Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS); + final Intent cancelJobsIntent = new Intent(TestJobActivity.ACTION_CANCEL_JOBS); cancelJobsIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY)); cancelJobsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(cancelJobsIntent); mContext.unregisterReceiver(mJobStateChangeReceiver); + Thread.sleep(500); // To avoid race with register in the next setUp setAppOpsModeAllowed(true); setPowerWhiteListed(false); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.FORCED_APP_STANDBY_ENABLED, 1); } private void setPowerWhiteListed(boolean whitelist) throws RemoteException { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java index 58f0ded9b9a1..a60d715c9abe 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java @@ -47,7 +47,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testSingleString() throws Exception { String[] expected = { "foobar" }; Bundle bundle = new Bundle(); - bundle.putString(Notification.EXTRA_PEOPLE, expected[0]); + bundle.putString(Notification.EXTRA_PEOPLE_LIST, expected[0]); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("string should be in result[0]", expected, result); } @@ -56,7 +56,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testSingleCharArray() throws Exception { String[] expected = { "foobar" }; Bundle bundle = new Bundle(); - bundle.putCharArray(Notification.EXTRA_PEOPLE, expected[0].toCharArray()); + bundle.putCharArray(Notification.EXTRA_PEOPLE_LIST, expected[0].toCharArray()); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("char[] should be in result[0]", expected, result); } @@ -65,7 +65,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testSingleCharSequence() throws Exception { String[] expected = { "foobar" }; Bundle bundle = new Bundle(); - bundle.putCharSequence(Notification.EXTRA_PEOPLE, new SpannableString(expected[0])); + bundle.putCharSequence(Notification.EXTRA_PEOPLE_LIST, new SpannableString(expected[0])); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("charSequence should be in result[0]", expected, result); } @@ -74,7 +74,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testStringArraySingle() throws Exception { Bundle bundle = new Bundle(); String[] expected = { "foobar" }; - bundle.putStringArray(Notification.EXTRA_PEOPLE, expected); + bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("wrapped string should be in result[0]", expected, result); } @@ -83,7 +83,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testStringArrayMultiple() throws Exception { Bundle bundle = new Bundle(); String[] expected = { "foo", "bar", "baz" }; - bundle.putStringArray(Notification.EXTRA_PEOPLE, expected); + bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testStringArrayMultiple", expected, result); } @@ -92,7 +92,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { public void testStringArrayNulls() throws Exception { Bundle bundle = new Bundle(); String[] expected = { "foo", null, "baz" }; - bundle.putStringArray(Notification.EXTRA_PEOPLE, expected); + bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testStringArrayNulls", expected, result); } @@ -105,7 +105,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { for (int i = 0; i < expected.length; i++) { charSeqArray[i] = new SpannableString(expected[i]); } - bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray); + bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result); } @@ -122,7 +122,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { charSeqArray[i] = new SpannableString(expected[i]); } } - bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray); + bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result); } @@ -135,7 +135,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { for (int i = 0; i < expected.length; i++) { stringArrayList.add(expected[i]); } - bundle.putStringArrayList(Notification.EXTRA_PEOPLE, stringArrayList); + bundle.putStringArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testStringArrayList", expected, result); } @@ -149,11 +149,24 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { for (int i = 0; i < expected.length; i++) { stringArrayList.add(new SpannableString(expected[i])); } - bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE, stringArrayList); + bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList); String[] result = ValidateNotificationPeople.getExtraPeople(bundle); assertStringArrayEquals("testCharSequenceArrayList", expected, result); } + @Test + public void testPeopleArrayList() throws Exception { + Bundle bundle = new Bundle(); + String[] expected = { "name:test" , "tel:1234" }; + final ArrayList<Notification.Person> arrayList = + new ArrayList<>(expected.length); + arrayList.add(new Notification.Person().setName("test")); + arrayList.add(new Notification.Person().setUri(expected[1])); + bundle.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, arrayList); + String[] result = ValidateNotificationPeople.getExtraPeople(bundle); + assertStringArrayEquals("testPeopleArrayList", expected, result); + } + private void assertStringArrayEquals(String message, String[] expected, String[] result) { String expectedString = Arrays.toString(expected); String resultString = Arrays.toString(result); diff --git a/telephony/java/android/telephony/data/ApnSetting.aidl b/telephony/java/android/telephony/data/ApnSetting.aidl new file mode 100644 index 000000000000..381e5e8a3a5e --- /dev/null +++ b/telephony/java/android/telephony/data/ApnSetting.aidl @@ -0,0 +1,18 @@ +/* + * 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 android.telephony.data; + +parcelable ApnSetting; diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java new file mode 100644 index 000000000000..2ab8d4fb900e --- /dev/null +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -0,0 +1,1370 @@ +/* + * 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 android.telephony.data; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.StringDef; +import android.content.ContentValues; +import android.database.Cursor; +import android.hardware.radio.V1_0.ApnTypes; +import android.net.NetworkUtils; +import android.os.Parcel; +import android.os.Parcelable; +import android.provider.Telephony; +import android.telephony.Rlog; +import android.text.TextUtils; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.MalformedURLException; +import java.net.UnknownHostException; +import java.net.URL; +import java.net.InetAddress; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * A class representing an APN configuration. + */ +public class ApnSetting implements Parcelable { + + static final String LOG_TAG = "ApnSetting"; + private static final boolean VDBG = false; + + private final String mEntryName; + private final String mApnName; + private final InetAddress mProxy; + private final int mPort; + private final URL mMmsc; + private final InetAddress mMmsProxy; + private final int mMmsPort; + private final String mUser; + private final String mPassword; + private final int mAuthType; + private final List<String> mTypes; + private final int mTypesBitmap; + private final int mId; + private final String mOperatorNumeric; + private final String mProtocol; + private final String mRoamingProtocol; + private final int mMtu; + + private final boolean mCarrierEnabled; + private final int mBearer; + private final int mBearerBitmask; + + private final int mProfileId; + + private final boolean mModemCognitive; + private final int mMaxConns; + private final int mWaitTime; + private final int mMaxConnsTime; + + private final String mMvnoType; + private final String mMvnoMatchData; + + private boolean mPermanentFailed = false; + + /** + * Returns the types bitmap of the APN. + * + * @return types bitmap of the APN + * @hide + */ + public int getTypesBitmap() { + return mTypesBitmap; + } + + /** + * Returns the MTU size of the mobile interface to which the APN connected. + * + * @return the MTU size of the APN + * @hide + */ + public int getMtu() { + return mMtu; + } + + /** + * Radio Access Technology info. + * To check what values can hold, refer to ServiceState.java. + * This should be spread to other technologies, + * but currently only used for LTE(14) and EHRPD(13). + * + * @return the bearer info of the APN + * @hide + */ + public int getBearer() { + return mBearer; + } + + /** + * Returns the radio access technology bitmask for this APN. + * + * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio + * technologies in ServiceState. + * This should be spread to other technologies, + * but currently only used for LTE(14) and EHRPD(13). + * + * @return the radio access technology bitmask + * @hide + */ + public int getBearerBitmask() { + return mBearerBitmask; + } + + /** + * Returns the profile id to which the APN saved in modem. + * + * @return the profile id of the APN + * @hide + */ + public int getProfileId() { + return mProfileId; + } + + /** + * Returns if the APN setting is to be set in modem. + * + * @return is the APN setting to be set in modem + * @hide + */ + public boolean getModemCognitive() { + return mModemCognitive; + } + + /** + * Returns the max connections of this APN. + * + * @return the max connections of this APN + * @hide + */ + public int getMaxConns() { + return mMaxConns; + } + + /** + * Returns the wait time for retry of the APN. + * + * @return the wait time for retry of the APN + * @hide + */ + public int getWaitTime() { + return mWaitTime; + } + + /** + * Returns the time to limit max connection for the APN. + * + * @return the time to limit max connection for the APN + * @hide + */ + public int getMaxConnsTime() { + return mMaxConnsTime; + } + + /** + * Returns the MVNO data. Examples: + * "spn": A MOBILE, BEN NL + * "imsi": 302720x94, 2060188 + * "gid": 4E, 33 + * "iccid": 898603 etc.. + * + * @return the mvno match data + * @hide + */ + public String getMvnoMatchData() { + return mMvnoMatchData; + } + + /** + * Indicates this APN setting is permanently failed and cannot be + * retried by the retry manager anymore. + * + * @return if this APN setting is permanently failed + * @hide + */ + public boolean getPermanentFailed() { + return mPermanentFailed; + } + + /** + * Sets if this APN setting is permanently failed. + * + * @param permanentFailed if this APN setting is permanently failed + * @hide + */ + public void setPermanentFailed(boolean permanentFailed) { + mPermanentFailed = permanentFailed; + } + + /** + * Returns the entry name of the APN. + * + * @return the entry name for the APN + */ + public String getEntryName() { + return mEntryName; + } + + /** + * Returns the name of the APN. + * + * @return APN name + */ + public String getApnName() { + return mApnName; + } + + /** + * Returns the proxy address of the APN. + * + * @return proxy address. + */ + public InetAddress getProxy() { + return mProxy; + } + + /** + * Returns the proxy port of the APN. + * + * @return proxy port + */ + public int getPort() { + return mPort; + } + /** + * Returns the MMSC URL of the APN. + * + * @return MMSC URL. + */ + public URL getMmsc() { + return mMmsc; + } + + /** + * Returns the MMS proxy address of the APN. + * + * @return MMS proxy address. + */ + public InetAddress getMmsProxy() { + return mMmsProxy; + } + + /** + * Returns the MMS proxy port of the APN. + * + * @return MMS proxy port + */ + public int getMmsPort() { + return mMmsPort; + } + + /** + * Returns the APN username of the APN. + * + * @return APN username + */ + public String getUser() { + return mUser; + } + + /** + * Returns the APN password of the APN. + * + * @return APN password + */ + public String getPassword() { + return mPassword; + } + + /** @hide */ + @IntDef({ + AUTH_TYPE_NONE, + AUTH_TYPE_PAP, + AUTH_TYPE_CHAP, + AUTH_TYPE_PAP_OR_CHAP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthType {} + + /** + * Returns the authentication type of the APN. + * + * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. + * + * @return authentication type + */ + @AuthType + public int getAuthType() { + return mAuthType; + } + + /** @hide */ + @StringDef({ + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ApnType {} + + /** + * Returns the list of APN types of the APN. + * + * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + * + * @return the list of APN types + */ + @ApnType + public List<String> getTypes() { + return mTypes; + } + + /** + * Returns the unique database id for this entry. + * + * @return the unique database id + */ + public int getId() { + return mId; + } + + /** + * Returns the numeric operator ID for the APN. Usually + * {@link android.provider.Telephony.Carriers#MCC} + + * {@link android.provider.Telephony.Carriers#MNC}. + * + * @return the numeric operator ID + */ + public String getOperatorNumeric() { + return mOperatorNumeric; + } + + /** @hide */ + @StringDef({ + PROTOCOL_IP, + PROTOCOL_IPV6, + PROTOCOL_IPV4V6, + PROTOCOL_PPP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ProtocolType {} + + /** + * Returns the protocol to use to connect to this APN. + * + * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. + * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + * + * @return the protocol + */ + @ProtocolType + public String getProtocol() { + return mProtocol; + } + + /** + * Returns the protocol to use to connect to this APN when roaming. + * + * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}. + * + * @return the roaming protocol + */ + public String getRoamingProtocol() { + return mRoamingProtocol; + } + + /** + * Returns the current status of APN. + * + * {@code true} : enabled APN. + * {@code false} : disabled APN. + * + * @return the current status + */ + public boolean isEnabled() { + return mCarrierEnabled; + } + + /** @hide */ + @StringDef({ + MVNO_TYPE_SPN, + MVNO_TYPE_IMSI, + MVNO_TYPE_GID, + MVNO_TYPE_ICCID, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MvnoType {} + + /** + * Returns the MVNO match type for this APN. + * + * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. + * + * @return the MVNO match type + */ + @MvnoType + public String getMvnoType() { + return mMvnoType; + } + + private ApnSetting(Builder builder) { + this.mEntryName = builder.mEntryName; + this.mApnName = builder.mApnName; + this.mProxy = builder.mProxy; + this.mPort = builder.mPort; + this.mMmsc = builder.mMmsc; + this.mMmsProxy = builder.mMmsProxy; + this.mMmsPort = builder.mMmsPort; + this.mUser = builder.mUser; + this.mPassword = builder.mPassword; + this.mAuthType = builder.mAuthType; + this.mTypes = (builder.mTypes == null ? new ArrayList<String>() : builder.mTypes); + this.mTypesBitmap = builder.mTypesBitmap; + this.mId = builder.mId; + this.mOperatorNumeric = builder.mOperatorNumeric; + this.mProtocol = builder.mProtocol; + this.mRoamingProtocol = builder.mRoamingProtocol; + this.mMtu = builder.mMtu; + this.mCarrierEnabled = builder.mCarrierEnabled; + this.mBearer = builder.mBearer; + this.mBearerBitmask = builder.mBearerBitmask; + this.mProfileId = builder.mProfileId; + this.mModemCognitive = builder.mModemCognitive; + this.mMaxConns = builder.mMaxConns; + this.mWaitTime = builder.mWaitTime; + this.mMaxConnsTime = builder.mMaxConnsTime; + this.mMvnoType = builder.mMvnoType; + this.mMvnoMatchData = builder.mMvnoMatchData; + } + + /** @hide */ + public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, + String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy, + int mmsPort, String user, String password, int authType, List<String> types, + String protocol, String roamingProtocol, boolean carrierEnabled, int bearer, + int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, + int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) { + return new Builder() + .setId(id) + .setOperatorNumeric(operatorNumeric) + .setEntryName(entryName) + .setApnName(apnName) + .setProxy(proxy) + .setPort(port) + .setMmsc(mmsc) + .setMmsProxy(mmsProxy) + .setMmsPort(mmsPort) + .setUser(user) + .setPassword(password) + .setAuthType(authType) + .setTypes(types) + .setProtocol(protocol) + .setRoamingProtocol(roamingProtocol) + .setCarrierEnabled(carrierEnabled) + .setBearer(bearer) + .setBearerBitmask(bearerBitmask) + .setProfileId(profileId) + .setModemCognitive(modemCognitive) + .setMaxConns(maxConns) + .setWaitTime(waitTime) + .setMaxConnsTime(maxConnsTime) + .setMtu(mtu) + .setMvnoType(mvnoType) + .setMvnoMatchData(mvnoMatchData) + .build(); + } + + /** @hide */ + public static ApnSetting makeApnSetting(Cursor cursor) { + String[] types = parseTypes( + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); + + return makeApnSetting( + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), + inetAddressFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), + URLFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), + inetAddressFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), + Arrays.asList(types), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.BEARER_BITMASK)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_COGNITIVE)) == 1, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MAX_CONNS_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_MATCH_DATA))); + } + + /** @hide */ + public static ApnSetting makeApnSetting(ApnSetting apn) { + return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, + apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser, + apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol, + apn.mCarrierEnabled, apn.mBearer, apn.mBearerBitmask, apn.mProfileId, + apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu, + apn.mMvnoType, apn.mMvnoMatchData); + } + + /** @hide */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[ApnSettingV3] ") + .append(mEntryName) + .append(", ").append(mId) + .append(", ").append(mOperatorNumeric) + .append(", ").append(mApnName) + .append(", ").append(inetAddressToString(mProxy)) + .append(", ").append(URLToString(mMmsc)) + .append(", ").append(inetAddressToString(mMmsProxy)) + .append(", ").append(portToString(mMmsPort)) + .append(", ").append(portToString(mPort)) + .append(", ").append(mAuthType).append(", "); + for (int i = 0; i < mTypes.size(); i++) { + sb.append(mTypes.get(i)); + if (i < mTypes.size() - 1) { + sb.append(" | "); + } + } + sb.append(", ").append(mProtocol); + sb.append(", ").append(mRoamingProtocol); + sb.append(", ").append(mCarrierEnabled); + sb.append(", ").append(mBearer); + sb.append(", ").append(mBearerBitmask); + sb.append(", ").append(mProfileId); + sb.append(", ").append(mModemCognitive); + sb.append(", ").append(mMaxConns); + sb.append(", ").append(mWaitTime); + sb.append(", ").append(mMaxConnsTime); + sb.append(", ").append(mMtu); + sb.append(", ").append(mMvnoType); + sb.append(", ").append(mMvnoMatchData); + sb.append(", ").append(mPermanentFailed); + return sb.toString(); + } + + /** + * Returns true if there are MVNO params specified. + * @hide + */ + public boolean hasMvnoParams() { + return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData); + } + + /** @hide */ + public boolean canHandleType(String type) { + if (!mCarrierEnabled) return false; + boolean wildcardable = true; + if (TYPE_IA.equalsIgnoreCase(type)) wildcardable = false; + for (String t : mTypes) { + // DEFAULT handles all, and HIPRI is handled by DEFAULT + if (t.equalsIgnoreCase(type) + || (wildcardable && t.equalsIgnoreCase(TYPE_ALL)) + || (t.equalsIgnoreCase(TYPE_DEFAULT) + && type.equalsIgnoreCase(TYPE_HIPRI))) { + return true; + } + } + return false; + } + + // check whether the types of two APN same (even only one type of each APN is same) + private boolean typeSameAny(ApnSetting first, ApnSetting second) { + if (VDBG) { + StringBuilder apnType1 = new StringBuilder(first.mApnName + ": "); + for (int index1 = 0; index1 < first.mTypes.size(); index1++) { + apnType1.append(first.mTypes.get(index1)); + apnType1.append(","); + } + + StringBuilder apnType2 = new StringBuilder(second.mApnName + ": "); + for (int index1 = 0; index1 < second.mTypes.size(); index1++) { + apnType2.append(second.mTypes.get(index1)); + apnType2.append(","); + } + Rlog.d(LOG_TAG, "APN1: is " + apnType1); + Rlog.d(LOG_TAG, "APN2: is " + apnType2); + } + + for (int index1 = 0; index1 < first.mTypes.size(); index1++) { + for (int index2 = 0; index2 < second.mTypes.size(); index2++) { + if (first.mTypes.get(index1).equals(ApnSetting.TYPE_ALL) + || second.mTypes.get(index2).equals(ApnSetting.TYPE_ALL) + || first.mTypes.get(index1).equals(second.mTypes.get(index2))) { + if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true"); + return true; + } + } + } + + if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false"); + return false; + } + + // TODO - if we have this function we should also have hashCode. + // Also should handle changes in type order and perhaps case-insensitivity + /** @hide */ + public boolean equals(Object o) { + if (o instanceof ApnSetting == false) { + return false; + } + + ApnSetting other = (ApnSetting) o; + + return mEntryName.equals(other.mEntryName) + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxy, other.mMmsProxy) + && Objects.equals(mMmsPort, other.mMmsPort) + && Objects.equals(mPort,other.mPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mTypes, other.mTypes) + && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mBearer, other.mBearer) + && Objects.equals(mBearerBitmask, other.mBearerBitmask) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData); + } + + /** + * Compare two APN settings + * + * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for + * determining if tearing a data call is needed when conditions change. See + * cleanUpConnectionsOnUpdatedApns in DcTracker. + * + * @param o the other object to compare + * @param isDataRoaming True if the device is on data roaming + * @return True if the two APN settings are same + * @hide + */ + public boolean equals(Object o, boolean isDataRoaming) { + if (!(o instanceof ApnSetting)) { + return false; + } + + ApnSetting other = (ApnSetting) o; + + return mEntryName.equals(other.mEntryName) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxy, other.mMmsProxy) + && Objects.equals(mMmsPort, other.mMmsPort) + && Objects.equals(mPort, other.mPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mTypes, other.mTypes) + && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData); + } + + /** + * Check if neither mention DUN and are substantially similar + * + * @param other The other APN settings to compare + * @return True if two APN settings are similar + * @hide + */ + public boolean similar(ApnSetting other) { + return (!this.canHandleType(TYPE_DUN) + && !other.canHandleType(TYPE_DUN) + && Objects.equals(this.mApnName, other.mApnName) + && !typeSameAny(this, other) + && xorEqualsInetAddress(this.mProxy, other.mProxy) + && xorEqualsPort(this.mPort, other.mPort) + && xorEquals(this.mProtocol, other.mProtocol) + && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(this.mBearerBitmask, other.mBearerBitmask) + && Objects.equals(this.mProfileId, other.mProfileId) + && Objects.equals(this.mMvnoType, other.mMvnoType) + && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) + && xorEqualsURL(this.mMmsc, other.mMmsc) + && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy) + && xorEqualsPort(this.mMmsPort, other.mMmsPort)); + } + + // Equal or one is not specified. + private boolean xorEquals(String first, String second) { + return (Objects.equals(first, second) + || TextUtils.isEmpty(first) + || TextUtils.isEmpty(second)); + } + + // Equal or one is not specified. + private boolean xorEqualsInetAddress(InetAddress first, InetAddress second) { + return first == null || second == null || first.equals(second); + } + + // Equal or one is not specified. + private boolean xorEqualsURL(URL first, URL second) { + return first == null || second == null || first.equals(second); + } + + // Equal or one is not specified. + private boolean xorEqualsPort(int first, int second) { + return first == -1 || second == -1 || Objects.equals(first, second); + } + + // Helper function to convert APN string into a 32-bit bitmask. + private static int getApnBitmask(String apn) { + switch (apn) { + case TYPE_DEFAULT: return ApnTypes.DEFAULT; + case TYPE_MMS: return ApnTypes.MMS; + case TYPE_SUPL: return ApnTypes.SUPL; + case TYPE_DUN: return ApnTypes.DUN; + case TYPE_HIPRI: return ApnTypes.HIPRI; + case TYPE_FOTA: return ApnTypes.FOTA; + case TYPE_IMS: return ApnTypes.IMS; + case TYPE_CBS: return ApnTypes.CBS; + case TYPE_IA: return ApnTypes.IA; + case TYPE_EMERGENCY: return ApnTypes.EMERGENCY; + case TYPE_ALL: return ApnTypes.ALL; + default: return ApnTypes.NONE; + } + } + + private String deParseTypes(List<String> types) { + if (types == null) { + return null; + } + return TextUtils.join(",", types); + } + + /** @hide */ + // Called by DPM. + public ContentValues toContentValues() { + ContentValues apnValue = new ContentValues(); + if (mOperatorNumeric != null) { + apnValue.put(Telephony.Carriers.NUMERIC, mOperatorNumeric); + } + if (mEntryName != null) { + apnValue.put(Telephony.Carriers.NAME, mEntryName); + } + if (mApnName != null) { + apnValue.put(Telephony.Carriers.APN, mApnName); + } + if (mProxy != null) { + apnValue.put(Telephony.Carriers.PROXY, inetAddressToString(mProxy)); + } + apnValue.put(Telephony.Carriers.PORT, portToString(mPort)); + if (mMmsc != null) { + apnValue.put(Telephony.Carriers.MMSC, URLToString(mMmsc)); + } + apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort)); + if (mMmsProxy != null) { + apnValue.put(Telephony.Carriers.MMSPROXY, inetAddressToString(mMmsProxy)); + } + if (mUser != null) { + apnValue.put(Telephony.Carriers.USER, mUser); + } + if (mPassword != null) { + apnValue.put(Telephony.Carriers.PASSWORD, mPassword); + } + apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType); + String apnType = deParseTypes(mTypes); + if (apnType != null) { + apnValue.put(Telephony.Carriers.TYPE, apnType); + } + if (mProtocol != null) { + apnValue.put(Telephony.Carriers.PROTOCOL, mProtocol); + } + if (mRoamingProtocol != null) { + apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, mRoamingProtocol); + } + apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled); + // networkTypeBit. + apnValue.put(Telephony.Carriers.BEARER_BITMASK, mBearerBitmask); + if (mMvnoType != null) { + apnValue.put(Telephony.Carriers.MVNO_TYPE, mMvnoType); + } + + return apnValue; + } + + /** + * @param types comma delimited list of APN types + * @return array of APN types + * @hide + */ + public static String[] parseTypes(String types) { + String[] result; + // If unset, set to DEFAULT. + if (TextUtils.isEmpty(types)) { + result = new String[1]; + result[0] = TYPE_ALL; + } else { + result = types.split(","); + } + return result; + } + + private static URL URLFromString(String url) { + try { + return TextUtils.isEmpty(url) ? null : new URL(url); + } catch (MalformedURLException e) { + Log.e(LOG_TAG, "Can't parse URL from string."); + return null; + } + } + + private static String URLToString(URL url) { + return url == null ? "" : url.toString(); + } + + private static InetAddress inetAddressFromString(String inetAddress) { + if (TextUtils.isEmpty(inetAddress)) { + return null; + } + try { + return InetAddress.getByName(inetAddress); + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "Can't parse InetAddress from string: unknown host."); + return null; + } + } + + private static String inetAddressToString(InetAddress inetAddress) { + if (inetAddress == null) { + return null; + } + return TextUtils.isEmpty(inetAddress.getHostName()) + ? inetAddress.getHostAddress() : inetAddress.getHostName(); + } + + private static int portFromString(String strPort) { + int port = -1; + if (!TextUtils.isEmpty(strPort)) { + try { + port = Integer.parseInt(strPort); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Can't parse port from String"); + } + } + return port; + } + + private static String portToString(int port) { + return port == -1 ? "" : Integer.toString(port); + } + + // Implement Parcelable. + @Override + /** @hide */ + public int describeContents() { + return 0; + } + + @Override + /** @hide */ + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mId); + dest.writeString(mOperatorNumeric); + dest.writeString(mEntryName); + dest.writeString(mApnName); + dest.writeValue(mProxy); + dest.writeInt(mPort); + dest.writeValue(mMmsc); + dest.writeValue(mMmsProxy); + dest.writeInt(mMmsPort); + dest.writeString(mUser); + dest.writeString(mPassword); + dest.writeInt(mAuthType); + dest.writeStringArray(mTypes.toArray(new String[0])); + dest.writeString(mProtocol); + dest.writeString(mRoamingProtocol); + dest.writeInt(mCarrierEnabled ? 1: 0); + dest.writeString(mMvnoType); + } + + private static ApnSetting readFromParcel(Parcel in) { + return makeApnSetting(in.readInt(), in.readString(), in.readString(), in.readString(), + (InetAddress)in.readValue(InetAddress.class.getClassLoader()), + in.readInt(), (URL)in.readValue(URL.class.getClassLoader()), + (InetAddress)in.readValue(InetAddress.class.getClassLoader()), + in.readInt(), in.readString(), in.readString(), in.readInt(), + Arrays.asList(in.readStringArray()), in.readString(), in.readString(), + in.readInt() > 0, 0, 0, 0, false, 0, 0, 0, 0, in.readString(), null); + } + + public static final Parcelable.Creator<ApnSetting> CREATOR = + new Parcelable.Creator<ApnSetting>() { + @Override + public ApnSetting createFromParcel(Parcel in) { + return readFromParcel(in); + } + + @Override + public ApnSetting[] newArray(int size) { + return new ApnSetting[size]; + } + }; + + /** + * APN types for data connections. These are usage categories for an APN + * entry. One APN entry may support multiple APN types, eg, a single APN + * may service regular internet traffic ("default") as well as MMS-specific + * connections.<br/> + * ALL is a special type to indicate that this APN entry can + * service all data connections. + */ + public static final String TYPE_ALL = "*"; + /** APN type for default data traffic */ + public static final String TYPE_DEFAULT = "default"; + /** APN type for MMS traffic */ + public static final String TYPE_MMS = "mms"; + /** APN type for SUPL assisted GPS */ + public static final String TYPE_SUPL = "supl"; + /** APN type for DUN traffic */ + public static final String TYPE_DUN = "dun"; + /** APN type for HiPri traffic */ + public static final String TYPE_HIPRI = "hipri"; + /** APN type for FOTA */ + public static final String TYPE_FOTA = "fota"; + /** APN type for IMS */ + public static final String TYPE_IMS = "ims"; + /** APN type for CBS */ + public static final String TYPE_CBS = "cbs"; + /** APN type for IA Initial Attach APN */ + public static final String TYPE_IA = "ia"; + /** APN type for Emergency PDN. This is not an IA apn, but is used + * for access to carrier services in an emergency call situation. */ + public static final String TYPE_EMERGENCY = "emergency"; + /** + * Array of all APN types + * + * @hide + */ + public static final String[] ALL_TYPES = { + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY + }; + + // Possible values for authentication types. + public static final int AUTH_TYPE_NONE = 0; + public static final int AUTH_TYPE_PAP = 1; + public static final int AUTH_TYPE_CHAP = 2; + public static final int AUTH_TYPE_PAP_OR_CHAP = 3; + + // Possible values for protocol. + public static final String PROTOCOL_IP = "IP"; + public static final String PROTOCOL_IPV6 = "IPV6"; + public static final String PROTOCOL_IPV4V6 = "IPV4V6"; + public static final String PROTOCOL_PPP = "PPP"; + + // Possible values for MVNO type. + public static final String MVNO_TYPE_SPN = "spn"; + public static final String MVNO_TYPE_IMSI = "imsi"; + public static final String MVNO_TYPE_GID = "gid"; + public static final String MVNO_TYPE_ICCID = "iccid"; + + public static class Builder{ + private String mEntryName; + private String mApnName; + private InetAddress mProxy; + private int mPort = -1; + private URL mMmsc; + private InetAddress mMmsProxy; + private int mMmsPort = -1; + private String mUser; + private String mPassword; + private int mAuthType; + private List<String> mTypes; + private int mTypesBitmap; + private int mId; + private String mOperatorNumeric; + private String mProtocol; + private String mRoamingProtocol; + private int mMtu; + private boolean mCarrierEnabled; + private int mBearer; + private int mBearerBitmask; + private int mProfileId; + private boolean mModemCognitive; + private int mMaxConns; + private int mWaitTime; + private int mMaxConnsTime; + private String mMvnoType; + private String mMvnoMatchData; + + /** + * Default constructor for Builder. + */ + public Builder() {} + + /** + * Set the MTU size of the mobile interface to which the APN connected. + * + * @param mtu the MTU size to set for the APN + * @hide + */ + public Builder setMtu(int mtu) { + this.mMtu = mtu; + return this; + } + + /** + * Sets bearer info. + * + * @param bearer the bearer info to set for the APN + * @hide + */ + public Builder setBearer(int bearer) { + this.mBearer = bearer; + return this; + } + + /** + * Sets the radio access technology bitmask for this APN. + * + * @param bearerBitmask the radio access technology bitmask to set for this APN + * @hide + */ + public Builder setBearerBitmask(int bearerBitmask) { + this.mBearerBitmask = bearerBitmask; + return this; + } + + /** + * Sets the profile id to which the APN saved in modem. + * + * @param profileId the profile id to set for the APN + * @hide + */ + public Builder setProfileId(int profileId) { + this.mProfileId = profileId; + return this; + } + + /** + * Sets if the APN setting is to be set in modem. + * + * @param modemCognitive if the APN setting is to be set in modem + * @hide + */ + public Builder setModemCognitive(boolean modemCognitive) { + this.mModemCognitive = modemCognitive; + return this; + } + + /** + * Sets the max connections of this APN. + * + * @param maxConns the max connections of this APN + * @hide + */ + public Builder setMaxConns(int maxConns) { + this.mMaxConns = maxConns; + return this; + } + + /** + * Sets the wait time for retry of the APN. + * + * @param waitTime the wait time for retry of the APN + * @hide + */ + public Builder setWaitTime(int waitTime) { + this.mWaitTime = waitTime; + return this; + } + + /** + * Sets the time to limit max connection for the APN. + * + * @param maxConnsTime the time to limit max connection for the APN + * @hide + */ + public Builder setMaxConnsTime(int maxConnsTime) { + this.mMaxConnsTime = maxConnsTime; + return this; + } + + /** + * Sets the MVNO match data for the APN. + * + * @param mvnoMatchData the MVNO match data for the APN + * @hide + */ + public Builder setMvnoMatchData(String mvnoMatchData) { + this.mMvnoMatchData = mvnoMatchData; + return this; + } + + /** + * Sets the entry name of the APN. + * + * @param entryName the entry name to set for the APN + */ + public Builder setEntryName(String entryName) { + this.mEntryName = entryName; + return this; + } + + /** + * Sets the name of the APN. + * + * @param apnName the name to set for the APN + */ + public Builder setApnName(String apnName) { + this.mApnName = apnName; + return this; + } + + /** + * Sets the proxy address of the APN. + * + * @param proxy the proxy address to set for the APN + */ + public Builder setProxy(InetAddress proxy) { + this.mProxy = proxy; + return this; + } + + /** + * Sets the proxy port of the APN. + * + * @param port the proxy port to set for the APN + */ + public Builder setPort(int port) { + this.mPort = port; + return this; + } + + /** + * Sets the MMSC URL of the APN. + * + * @param mmsc the MMSC URL to set for the APN + */ + public Builder setMmsc(URL mmsc) { + this.mMmsc = mmsc; + return this; + } + + /** + * Sets the MMS proxy address of the APN. + * + * @param mmsProxy the MMS proxy address to set for the APN + */ + public Builder setMmsProxy(InetAddress mmsProxy) { + this.mMmsProxy = mmsProxy; + return this; + } + + /** + * Sets the MMS proxy port of the APN. + * + * @param mmsPort the MMS proxy port to set for the APN + */ + public Builder setMmsPort(int mmsPort) { + this.mMmsPort = mmsPort; + return this; + } + + /** + * Sets the APN username of the APN. + * + * @param user the APN username to set for the APN + */ + public Builder setUser(String user) { + this.mUser = user; + return this; + } + + /** + * Sets the APN password of the APN. + * + * @see android.provider.Telephony.Carriers#PASSWORD + * @param password the APN password to set for the APN + */ + public Builder setPassword(String password) { + this.mPassword = password; + return this; + } + + /** + * Sets the authentication type of the APN. + * + * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. + * + * @param authType the authentication type to set for the APN + */ + public Builder setAuthType(@AuthType int authType) { + this.mAuthType = authType; + return this; + } + + /** + * Sets the list of APN types of the APN. + * + * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + * + * @param types the list of APN types to set for the APN + */ + public Builder setTypes(@ApnType List<String> types) { + this.mTypes = types; + int apnBitmap = 0; + for (int i = 0; i < mTypes.size(); i++) { + mTypes.set(i, mTypes.get(i).toLowerCase()); + apnBitmap |= getApnBitmask(mTypes.get(i)); + } + this.mTypesBitmap = apnBitmap; + return this; + } + + /** + * Sets the unique database id for this entry. + * + * @param id the unique database id to set for this entry + */ + public Builder setId(int id) { + this.mId = id; + return this; + } + + /** + * Set the numeric operator ID for the APN. + * + * @param operatorNumeric the numeric operator ID to set for this entry + */ + public Builder setOperatorNumeric(String operatorNumeric) { + this.mOperatorNumeric = operatorNumeric; + return this; + } + + /** + * Sets the protocol to use to connect to this APN. + * + * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. + * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + * + * @param protocol the protocol to set to use to connect to this APN + */ + public Builder setProtocol(@ProtocolType String protocol) { + this.mProtocol = protocol; + return this; + } + + /** + * Sets the protocol to use to connect to this APN when roaming. + * + * @param roamingProtocol the protocol to set to use to connect to this APN when roaming + */ + public Builder setRoamingProtocol(String roamingProtocol) { + this.mRoamingProtocol = roamingProtocol; + return this; + } + + /** + * Sets the current status of APN. + * + * @param carrierEnabled the current status to set for this APN + */ + public Builder setCarrierEnabled(boolean carrierEnabled) { + this.mCarrierEnabled = carrierEnabled; + return this; + } + + /** + * Sets the MVNO match type for this APN. + * + * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. + * + * @param mvnoType the MVNO match type to set for this APN + */ + public Builder setMvnoType(@MvnoType String mvnoType) { + this.mMvnoType = mvnoType; + return this; + } + + public ApnSetting build() { + return new ApnSetting(this); + } + } +} + diff --git a/core/tests/coretests/src/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java index 8d51c3b01258..8d51c3b01258 100644 --- a/core/tests/coretests/src/android/net/NetworkUtilsTest.java +++ b/tests/net/java/android/net/NetworkUtilsTest.java diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/tests/net/java/android/net/RouteInfoTest.java index 831fefd283db..831fefd283db 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/tests/net/java/android/net/RouteInfoTest.java diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 725ddb9ccbca..9b75a509288f 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -35,6 +35,7 @@ import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.os.ConditionVariable; import android.os.Parcelable; import android.os.SystemClock; @@ -62,7 +63,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; -import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; import java.util.Random; @@ -635,7 +635,7 @@ public class ApfTest { public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception { - super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log); + super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log); } // Pretend an RA packet has been received and show it to ApfFilter. diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java index 54776dbd3c52..e65585f8ff0f 100644 --- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java +++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; +import android.net.util.InterfaceParams; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -54,8 +55,8 @@ public class IpReachabilityMonitorTest { } IpReachabilityMonitor makeMonitor() { - return new IpReachabilityMonitor( - "fake0", 1, mHandler, mLog, mCallback, null, mDependencies); + final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null); + return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies); } @Test diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java index 38d3d74e64cf..f9b7ec8f0322 100644 --- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java +++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java @@ -20,6 +20,7 @@ import static android.net.util.NetworkConstants.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.net.MacAddress; import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; @@ -36,9 +37,7 @@ import libcore.util.HexEncoding; @RunWith(AndroidJUnit4.class) @SmallTest public class ConnectivityPacketSummaryTest { - private static final byte[] MYHWADDR = { - asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3) - }; + private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3"); private String getSummary(String hexBytes) { hexBytes = hexBytes.replaceAll("\\s+", ""); diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java new file mode 100644 index 000000000000..21728afdd5de --- /dev/null +++ b/tests/net/java/android/net/util/InterfaceParamsTest.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package android.net.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceParamsTest { + @Test + public void testNullInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName(null)); + } + + @Test + public void testNonExistentInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName("doesnotexist0")); + } + + @Test + public void testLoopback() { + final InterfaceParams ifParams = InterfaceParams.getByName("lo"); + assertNotNull(ifParams); + assertEquals("lo", ifParams.name); + assertTrue(ifParams.index > 0); + assertNotNull(ifParams.macAddr); + assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU); + } +} |