diff options
670 files changed, 17600 insertions, 6929 deletions
diff --git a/Android.bp b/Android.bp index 3e471b63498e..faad6f32dec4 100644 --- a/Android.bp +++ b/Android.bp @@ -77,6 +77,7 @@ java_defaults {          "core/java/android/app/ISearchManager.aidl",          "core/java/android/app/ISearchManagerCallback.aidl",          "core/java/android/app/IServiceConnection.aidl", +        "core/java/android/app/ISmsAppService.aidl",          "core/java/android/app/IStopUserCallback.aidl",          "core/java/android/app/job/IJobCallback.aidl",          "core/java/android/app/job/IJobScheduler.aidl", @@ -706,7 +707,6 @@ java_defaults {      // Loaded with System.loadLibrary by android.view.textclassifier      required: [ -        "libtextclassifier",          "libmedia2_jni",      ], @@ -810,12 +810,16 @@ gensrcs {  java_library {      name: "ext",      installable: true, -    no_framework_libs: true, +    sdk_version: "core_current",      static_libs: [          "libphonenumber-platform",          "nist-sip",          "tagsoup",          "rappor", +        "libtextclassifier-java", +    ], +    required: [ +        "libtextclassifier",      ],      dxflags: ["--core-library"],  } diff --git a/CleanSpec.mk b/CleanSpec.mk index 2247e43758d7..6deda0caa9aa 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -247,6 +247,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/statsd  $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.mediadrm.signer.jar)  $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.location.provider.jar)  $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.future.usb.accessory.jar) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.media.remotedisplay.jar)  # ******************************************************************  # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER  # ****************************************************************** diff --git a/api/current.txt b/api/current.txt index 52257c0f7529..e6a31afafa1d 100755 --- a/api/current.txt +++ b/api/current.txt @@ -7,6 +7,7 @@ package android {    public static final class Manifest.permission {      ctor public Manifest.permission();      field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER"; +    field public static final java.lang.String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";      field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";      field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";      field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; @@ -37,6 +38,7 @@ package android {      field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";      field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";      field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE"; +    field public static final java.lang.String BIND_SMS_APP_SERVICE = "android.permission.BIND_SMS_APP_SERVICE";      field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";      field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";      field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT"; @@ -772,9 +774,11 @@ package android {      field public static final int isFeatureSplit = 16844123; // 0x101055b      field public static final int isGame = 16843764; // 0x10103f4      field public static final int isIndicator = 16843079; // 0x1010147 +    field public static final int isLightTheme = 16844175; // 0x101058f      field public static final int isModifier = 16843334; // 0x1010246      field public static final int isRepeatable = 16843336; // 0x1010248      field public static final int isScrollContainer = 16843342; // 0x101024e +    field public static final int isSplitRequired = 16844176; // 0x1010590      field public static final int isStatic = 16844122; // 0x101055a      field public static final int isSticky = 16843335; // 0x1010247      field public static final int isolatedProcess = 16843689; // 0x10103a9 @@ -4296,6 +4300,20 @@ package android.app {      method public abstract void onActivityCreated(android.app.Activity, android.os.Bundle);      method public abstract void onActivityDestroyed(android.app.Activity);      method public abstract void onActivityPaused(android.app.Activity); +    method public default void onActivityPostCreated(android.app.Activity, android.os.Bundle); +    method public default void onActivityPostDestroyed(android.app.Activity); +    method public default void onActivityPostPaused(android.app.Activity); +    method public default void onActivityPostResumed(android.app.Activity); +    method public default void onActivityPostSaveInstanceState(android.app.Activity, android.os.Bundle); +    method public default void onActivityPostStarted(android.app.Activity); +    method public default void onActivityPostStopped(android.app.Activity); +    method public default void onActivityPreCreated(android.app.Activity, android.os.Bundle); +    method public default void onActivityPreDestroyed(android.app.Activity); +    method public default void onActivityPrePaused(android.app.Activity); +    method public default void onActivityPreResumed(android.app.Activity); +    method public default void onActivityPreSaveInstanceState(android.app.Activity, android.os.Bundle); +    method public default void onActivityPreStarted(android.app.Activity); +    method public default void onActivityPreStopped(android.app.Activity);      method public abstract void onActivityResumed(android.app.Activity);      method public abstract void onActivitySaveInstanceState(android.app.Activity, android.os.Bundle);      method public abstract void onActivityStarted(android.app.Activity); @@ -6095,6 +6113,11 @@ package android.app {      method public abstract void onSharedElementsReady();    } +  public class SmsAppService extends android.app.Service { +    ctor public SmsAppService(); +    method public final android.os.IBinder onBind(android.content.Intent); +  } +    public deprecated class TabActivity extends android.app.ActivityGroup {      ctor public TabActivity();      method public android.widget.TabHost getTabHost(); @@ -15314,7 +15337,7 @@ package android.graphics.fonts {      method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);    } -  public class SystemFonts { +  public final class SystemFonts {      method public static java.util.Set<android.graphics.fonts.Font> getAvailableFonts();    } @@ -21627,7 +21650,7 @@ package android.inputmethodservice {      method public android.view.inputmethod.InputConnection getCurrentInputConnection();      method public android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();      method public boolean getCurrentInputStarted(); -    method public int getInputMethodWindowRecommendedHeight(); +    method public deprecated int getInputMethodWindowRecommendedHeight();      method public android.view.LayoutInflater getLayoutInflater();      method public int getMaxWidth();      method public java.lang.CharSequence getTextForImeAction(int); @@ -32500,6 +32523,7 @@ package android.os {    public class Build {      ctor public Build(); +    method public static java.util.List<android.os.Build.Partition> getPartitions();      method public static java.lang.String getRadioVersion();      method public static java.lang.String getSerial();      field public static final java.lang.String BOARD; @@ -32528,6 +32552,14 @@ package android.os {      field public static final java.lang.String USER;    } +  public static class Build.Partition { +    ctor public Build.Partition(); +    method public java.lang.String getFingerprint(); +    method public java.lang.String getName(); +    method public long getTimeMillis(); +    field public static final java.lang.String PARTITION_NAME_SYSTEM = "system"; +  } +    public static class Build.VERSION {      ctor public Build.VERSION();      field public static final java.lang.String BASE_OS; @@ -33702,6 +33734,7 @@ package android.os {      field public static final java.lang.String DISALLOW_FUN = "no_fun";      field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";      field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources"; +    field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally";      field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";      field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";      field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset"; @@ -42547,7 +42580,7 @@ package android.telephony {      method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);    } -  public class NeighboringCellInfo implements android.os.Parcelable { +  public deprecated class NeighboringCellInfo implements android.os.Parcelable {      ctor public deprecated NeighboringCellInfo();      ctor public deprecated NeighboringCellInfo(int, int);      ctor public NeighboringCellInfo(int, java.lang.String, int); @@ -42920,6 +42953,7 @@ package android.telephony {      method public static int getSlotIndex(int);      method public static int[] getSubscriptionIds(int);      method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); +    method public boolean isActiveSubscriptionId(int);      method public boolean isNetworkRoaming(int);      method public static boolean isValidSubscriptionId(int);      method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); @@ -43007,7 +43041,6 @@ package android.telephony {      method public java.lang.String getMmsUAProfUrl();      method public java.lang.String getMmsUserAgent();      method public java.lang.String getNai(); -    method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();      method public java.lang.String getNetworkCountryIso();      method public java.lang.String getNetworkOperator();      method public java.lang.String getNetworkOperatorName(); @@ -43072,6 +43105,7 @@ package android.telephony {      field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";      field public static final java.lang.String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";      field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; +    field public static final java.lang.String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";      field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";      field public static final int APPTYPE_CSIM = 4; // 0x4      field public static final int APPTYPE_ISIM = 5; // 0x5 @@ -45017,11 +45051,20 @@ package android.text.style {      ctor public TextAppearanceSpan(android.os.Parcel);      method public int describeContents();      method public java.lang.String getFamily(); +    method public java.lang.String getFontFeatureSettings(); +    method public java.lang.String getFontVariationSettings();      method public android.content.res.ColorStateList getLinkTextColor(); +    method public int getShadowColor(); +    method public float getShadowDx(); +    method public float getShadowDy(); +    method public float getShadowRadius();      method public int getSpanTypeId();      method public android.content.res.ColorStateList getTextColor(); +    method public int getTextFontWeight();      method public int getTextSize();      method public int getTextStyle(); +    method public android.graphics.Typeface getTypeface(); +    method public boolean isElegantTextHeight();      method public void updateDrawState(android.text.TextPaint);      method public void updateMeasureState(android.text.TextPaint);      method public void writeToParcel(android.os.Parcel, int); @@ -45664,6 +45707,7 @@ package android.util {      method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();      method public V get(java.lang.Object);      method public int indexOfKey(java.lang.Object); +    method public int indexOfValue(java.lang.Object);      method public boolean isEmpty();      method public K keyAt(int);      method public java.util.Set<K> keySet(); @@ -45684,6 +45728,7 @@ package android.util {      ctor public ArraySet();      ctor public ArraySet(int);      ctor public ArraySet(android.util.ArraySet<E>); +    ctor public ArraySet(java.util.Collection<? extends E>);      method public boolean add(E);      method public void addAll(android.util.ArraySet<? extends E>);      method public boolean addAll(java.util.Collection<? extends E>); @@ -46255,6 +46300,7 @@ package android.util {      method public int keyAt(int);      method public void put(int, boolean);      method public void removeAt(int); +    method public void setValueAt(int, boolean);      method public int size();      method public boolean valueAt(int);    } @@ -46273,6 +46319,7 @@ package android.util {      method public int keyAt(int);      method public void put(int, int);      method public void removeAt(int); +    method public void setValueAt(int, int);      method public int size();      method public int valueAt(int);    } @@ -50290,7 +50337,7 @@ package android.view.animation {      method public long computeDurationHint();      method protected void ensureInterpolator();      method public int getBackgroundColor(); -    method public boolean getDetachWallpaper(); +    method public deprecated boolean getDetachWallpaper();      method public long getDuration();      method public boolean getFillAfter();      method public boolean getFillBefore(); @@ -50314,7 +50361,7 @@ package android.view.animation {      method public void scaleCurrentDuration(float);      method public void setAnimationListener(android.view.animation.Animation.AnimationListener);      method public void setBackgroundColor(int); -    method public void setDetachWallpaper(boolean); +    method public deprecated void setDetachWallpaper(boolean);      method public void setDuration(long);      method public void setFillAfter(boolean);      method public void setFillBefore(boolean); @@ -51407,7 +51454,7 @@ package android.webkit {    }    public abstract class CookieManager { -    ctor public CookieManager(); +    ctor public deprecated CookieManager();      method public abstract boolean acceptCookie();      method public abstract boolean acceptThirdPartyCookies(android.webkit.WebView);      method public static boolean allowFileSchemeCookies(); @@ -51507,13 +51554,13 @@ package android.webkit {    }    public abstract class RenderProcessGoneDetail { -    ctor public RenderProcessGoneDetail(); +    ctor public deprecated RenderProcessGoneDetail();      method public abstract boolean didCrash();      method public abstract int rendererPriorityAtExit();    }    public abstract class SafeBrowsingResponse { -    ctor public SafeBrowsingResponse(); +    ctor public deprecated SafeBrowsingResponse();      method public abstract void backToSafety(boolean);      method public abstract void proceed(boolean);      method public abstract void showInterstitial(boolean); @@ -51525,7 +51572,7 @@ package android.webkit {    }    public abstract class ServiceWorkerController { -    ctor public ServiceWorkerController(); +    ctor public deprecated ServiceWorkerController();      method public static android.webkit.ServiceWorkerController getInstance();      method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();      method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient); @@ -51574,7 +51621,7 @@ package android.webkit {    }    public abstract class TracingController { -    ctor public TracingController(); +    ctor public deprecated TracingController();      method public static android.webkit.TracingController getInstance();      method public abstract boolean isTracing();      method public abstract void start(android.webkit.TracingConfig); @@ -52114,7 +52161,7 @@ package android.webkit {    }    public abstract class WebViewDatabase { -    ctor public WebViewDatabase(); +    ctor public deprecated WebViewDatabase();      method public abstract deprecated void clearFormData();      method public abstract void clearHttpAuthUsernamePassword();      method public abstract deprecated void clearUsernamePassword(); @@ -55222,6 +55269,7 @@ package dalvik.system {    public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {      ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader);      ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader); +    ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader, boolean);    }    public class DexClassLoader extends dalvik.system.BaseDexClassLoader { diff --git a/api/removed.txt b/api/removed.txt index b6dabcd8614b..f7106d2207ec 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -545,6 +545,7 @@ package android.telephony {    }    public class TelephonyManager { +    method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();      method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);    } diff --git a/api/system-current.txt b/api/system-current.txt index 38ec39902522..b95a0857f3a3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5441,6 +5441,7 @@ package android.telephony {      method public boolean disableDataConnectivity();      method public boolean enableDataConnectivity();      method public void enableVideoCalling(boolean); +    method public java.lang.String getAidForAppType(int);      method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);      method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);      method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); @@ -5456,6 +5457,7 @@ package android.telephony {      method public deprecated boolean getDataEnabled(int);      method public boolean getEmergencyCallbackMode();      method public java.lang.String getIsimDomain(); +    method public int getPreferredNetworkType(int);      method public int getSimApplicationState();      method public int getSimCardState();      method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); @@ -5465,10 +5467,7 @@ package android.telephony {      method public boolean handlePinMmi(java.lang.String);      method public boolean handlePinMmiForSubscriber(int, java.lang.String);      method public boolean isDataConnectivityPossible(); -    method public deprecated boolean isIdle(); -    method public deprecated boolean isOffhook();      method public deprecated boolean isRadioOn(); -    method public deprecated boolean isRinging();      method public boolean isVideoCallingEnabled();      method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);      method public boolean needsOtaServiceProvisioning(); @@ -5482,7 +5481,6 @@ package android.telephony {      method public void setSimPowerStateForSlot(int, int);      method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);      method public void setVoiceActivationState(int); -    method public deprecated void silenceRinger();      method public boolean supplyPin(java.lang.String);      method public int[] supplyPinReportResult(java.lang.String);      method public boolean supplyPuk(java.lang.String, java.lang.String); @@ -5500,6 +5498,29 @@ package android.telephony {      field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";      field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";      field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; +    field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4 +    field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5 +    field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6 +    field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7 +    field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1 +    field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3 +    field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8 +    field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa +    field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9 +    field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb +    field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf +    field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16 +    field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11 +    field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14 +    field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13 +    field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc +    field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15 +    field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10 +    field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12 +    field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd +    field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe +    field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2 +    field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0      field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2      field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1      field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3 diff --git a/api/system-removed.txt b/api/system-removed.txt index 9012c3315cfe..22465621e693 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -148,6 +148,10 @@ package android.telephony {    public class TelephonyManager {      method public deprecated void answerRingingCall();      method public deprecated boolean endCall(); +    method public deprecated boolean isIdle(); +    method public deprecated boolean isOffhook(); +    method public deprecated boolean isRinging(); +    method public deprecated void silenceRinger();    }  } diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index d3496ed9798b..f6b0db80f3ad 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -99,6 +99,7 @@ statsd_common_shared_libraries := \      libhidlbase \      libhidltransport \      libhwbinder \ +    android.frameworks.stats@1.0 \      android.hardware.health@2.0 \      android.hardware.power@1.0 \      android.hardware.power@1.1 \ @@ -227,7 +228,8 @@ LOCAL_SRC_FILES := \      tests/e2e/Anomaly_count_e2e_test.cpp \      tests/e2e/Anomaly_duration_sum_e2e_test.cpp \      tests/e2e/ConfigTtl_e2e_test.cpp \ -    tests/e2e/PartialBucket_e2e_test.cpp +    tests/e2e/PartialBucket_e2e_test.cpp \ +    tests/shell/ShellSubscriber_test.cpp  LOCAL_STATIC_LIBRARIES := \      $(statsd_common_static_libraries) \ diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 2ef1169851ff..8da2d447a163 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -992,6 +992,60 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {      return Status::ok();  } +hardware::Return<void> StatsService::reportSpeakerImpedance( +        const SpeakerImpedance& speakerImpedance) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportHardwareFailed(const HardwareFailed& hardwareFailed) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), hardwareFailed); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportPhysicalDropDetected( +        const PhysicalDropDetected& physicalDropDetected) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), physicalDropDetected); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportChargeCycles(const ChargeCycles& chargeCycles) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), chargeCycles); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportBatteryHealthSnapshot( +        const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), +                   batteryHealthSnapshotArgs); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportSlowIo(const SlowIo& slowIo) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), slowIo); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} + +hardware::Return<void> StatsService::reportBatteryCausedShutdown( +        const BatteryCausedShutdown& batteryCausedShutdown) { +    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), batteryCausedShutdown); +    mProcessor->OnLogEvent(&event); + +    return hardware::Void(); +} +  void StatsService::binderDied(const wp <IBinder>& who) {      ALOGW("statscompanion service died");      StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec()); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 06189278abce..1f1d782af235 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -27,6 +27,8 @@  #include "shell/ShellSubscriber.h"  #include "statscompanion_util.h" +#include <android/frameworks/stats/1.0/IStats.h> +#include <android/frameworks/stats/1.0/types.h>  #include <android/os/BnStatsManager.h>  #include <android/os/IStatsCompanionService.h>  #include <binder/IResultReceiver.h> @@ -38,6 +40,7 @@  using namespace android;  using namespace android::base;  using namespace android::binder; +using namespace android::frameworks::stats::V1_0;  using namespace android::os;  using namespace std; @@ -45,7 +48,12 @@ namespace android {  namespace os {  namespace statsd { -class StatsService : public BnStatsManager, public LogListener, public IBinder::DeathRecipient { +using android::hardware::Return; + +class StatsService : public BnStatsManager, +                     public LogListener, +                     public IStats, +                     public IBinder::DeathRecipient {  public:      StatsService(const sp<Looper>& handlerLooper);      virtual ~StatsService(); @@ -146,6 +154,44 @@ public:       */      virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; +    /** +     * Binder call to get SpeakerImpedance atom. +     */ +    virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override; + +    /** +     * Binder call to get HardwareFailed atom. +     */ +    virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override; + +    /** +     * Binder call to get PhysicalDropDetected atom. +     */ +    virtual Return<void> reportPhysicalDropDetected( +            const PhysicalDropDetected& physicalDropDetected) override; + +    /** +     * Binder call to get ChargeCyclesReported atom. +     */ +    virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override; + +    /** +     * Binder call to get BatteryHealthSnapshot atom. +     */ +    virtual Return<void> reportBatteryHealthSnapshot( +            const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override; + +    /** +     * Binder call to get SlowIo atom. +     */ +    virtual Return<void> reportSlowIo(const SlowIo& slowIo) override; + +    /** +     * Binder call to get BatteryCausedShutdown atom. +     */ +    virtual Return<void> reportBatteryCausedShutdown( +            const BatteryCausedShutdown& batteryCausedShutdown) override; +      /** IBinder::DeathRecipient */      virtual void binderDied(const wp<IBinder>& who) override; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index ffd7d3161202..988ffc4d95b7 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -80,7 +80,8 @@ message Atom {          BatteryLevelChanged battery_level_changed = 30;          ChargingStateChanged charging_state_changed = 31;          PluggedStateChanged plugged_state_changed = 32; -        // 33 - 34 are available +        InteractiveStateChanged interactive_state_changed = 33; +        // 34 is available          WakeupAlarmOccurred wakeup_alarm_occurred = 35;          KernelWakeupReported kernel_wakeup_reported = 36;          WifiLockStateChanged wifi_lock_state_changed = 37; @@ -137,6 +138,9 @@ message Atom {          FingerprintAuthenticated fingerprint_authenticated = 88;          FingerprintErrorOccurred fingerprint_error_occurred = 89;          Notification notification = 90; +        BatteryHealthSnapshot battery_health_snapshot = 91; +        SlowIo slow_io = 92; +        BatteryCausedShutdown battery_caused_shutdown = 93;      }      // Pulled events will start at field 10000. @@ -174,6 +178,7 @@ message Atom {          BatteryVoltage battery_voltage = 10030;          NumFingerprints num_fingerprints = 10031;          ProcStats proc_stats = 10029; +        DiskIo disk_io = 10032;      }      // DO NOT USE field numbers above 100,000 in AOSP. @@ -199,9 +204,10 @@ message AttributionNode {  message KeyValuePair {      optional int32 key = 1;      oneof value { -        int64 value_int = 2; -        string value_str = 3; -        float value_float = 4; +        int32 value_int = 2; +        int64 value_long = 3; +        string value_str = 4; +        float value_float = 5;      }  } @@ -665,6 +671,20 @@ message LongPartialWakelockStateChanged {  }  /** + * Logs when the device is interactive, according to the PowerManager Notifier. + * + * Logged from: + *   frameworks/base/services/core/java/com/android/server/power/Notifier.java + */ +message InteractiveStateChanged { +    enum State { +        OFF = 0; +        ON = 1; +    } +    optional State state = 1; +} + +/**   * Logs Battery Saver state change.   *   * Logged from: @@ -754,6 +774,9 @@ message WakeupAlarmOccurred {      // Name of the wakeup alarm.      optional string tag = 2; + +    // Name of source package (for historical reasons, since BatteryStats tracked it). +    optional string package_name = 3;  }  /** @@ -1294,6 +1317,68 @@ message ChargeCyclesReported {  }  /** + * Log battery health snapshot. + * + * Resistance, Voltage, Open Circuit Voltage, Temperature, and Charge Level + * are snapshotted periodically over 24hrs. + */ +message BatteryHealthSnapshot { +    enum BatterySnapshotType { +        UNKNOWN = 0; +        MIN_TEMP = 1;         // Snapshot at min batt temp over 24hrs. +        MAX_TEMP = 2;         // Snapshot at max batt temp over 24hrs. +        MIN_RESISTANCE = 3;   // Snapshot at min batt resistance over 24hrs. +        MAX_RESISTANCE = 4;   // Snapshot at max batt resistance over 24hrs. +        MIN_VOLTAGE = 5;      // Snapshot at min batt voltage over 24hrs. +        MAX_VOLTAGE = 6;      // Snapshot at max batt voltage over 24hrs. +        MIN_CURRENT = 7;      // Snapshot at min batt current over 24hrs. +        MAX_CURRENT = 8;      // Snapshot at max batt current over 24hrs. +        MIN_BATT_LEVEL = 9;   // Snapshot at min battery level (SoC) over 24hrs. +        MAX_BATT_LEVEL = 10;  // Snapshot at max battery level (SoC) over 24hrs. +        AVG_RESISTANCE = 11;  // Snapshot at average battery resistance over 24hrs. +    } +    optional BatterySnapshotType type = 1; +    // Temperature, in 1/10ths of degree C. +    optional int32 temperature_deci_celcius = 2; +    // Voltage Battery Voltage, in microVolts. +    optional int32 voltage_micro_volt = 3; +    // Current Battery current, in microAmps. +    optional int32 current_micro_amps = 4; +    // OpenCircuitVoltage Battery Open Circuit Voltage, in microVolts. +    optional int32 open_circuit_micro_volt = 5; +    // Resistance Battery Resistance, in microOhms. +    optional int32 resistance_micro_ohm = 6; +    // Level Battery Level, as % of full. +    optional int32 level_percent = 7; +} + +/** + * Log slow I/O operations on the primary storage. + */ +message SlowIo { +    // Classifications of IO Operations. +    enum IoOperation { +        UNKNOWN = 0; +        READ = 1; +        WRITE = 2; +        UNMAP = 3; +        SYNC = 4; +    } +    optional IoOperation operation = 1; + +    // The number of slow IO operations of this type over 24 hours. +    optional int32 count = 2; +} + +/** + * Log battery caused shutdown with the last recorded voltage. + */ +message BatteryCausedShutdown { +    // The last recorded battery voltage prior to shutdown. +    optional int32 last_recorded_micro_volt = 1; +} + +/**   * Logs the duration of a davey (jank of >=700ms) when it occurs   *   * Logged from: @@ -2220,6 +2305,11 @@ message ProcessMemoryState {      // SWAP      optional int64 swap_in_bytes = 8; + +    // RSS high watermark. +    // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status or +    // from memory.max_usage_in_bytes under /dev/memcg if the device uses per-app memory cgroups. +    optional int64 rss_high_watermark_in_bytes = 9;  }  /* @@ -2533,6 +2623,30 @@ message CategorySize {  }  /** + * Pulls per uid I/O stats. The stats are cumulative since boot. + * + * Read/write bytes are I/O events from a storage device + * Read/write chars are data requested by read/write syscalls, and can be + *   satisfied by caching. + * + * Pulled from StatsCompanionService, which reads proc/uid_io/stats. + */ +message DiskIo { +    optional int32 uid = 1 [(is_uid) = true]; +    optional int64 fg_chars_read = 2; +    optional int64 fg_chars_write = 3; +    optional int64 fg_bytes_read = 4; +    optional int64 fg_bytes_write = 5; +    optional int64 bg_chars_read = 6; +    optional int64 bg_chars_write = 7; +    optional int64 bg_bytes_read = 8; +    optional int64 bg_bytes_write = 9; +    optional int64 fg_fsync = 10; +    optional int64 bg_fsync= 11; +} + + +/**   * Pulls the number of fingerprints for each user.   *   * Pulled from StatsCompanionService, which queries FingerprintManager. diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 5a0172b22301..fd8671406051 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -163,13 +163,10 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {            new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},          // battery_voltage          {android::util::BATTERY_VOLTAGE, -         {{}, -          {}, -          1 * NS_PER_SEC, -          new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}}, +         {{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},          // process_memory_state          {android::util::PROCESS_MEMORY_STATE, -         {{4, 5, 6, 7, 8}, +         {{4, 5, 6, 7, 8, 9},            {2, 3},            1 * NS_PER_SEC,            new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, @@ -204,17 +201,23 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {           {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},          // Size of specific categories of files. Eg. Music.          {android::util::CATEGORY_SIZE, -         {{}, -          {}, -          1 * NS_PER_SEC, -          new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, +         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},          // Number of fingerprints registered to each user.          {android::util::NUM_FINGERPRINTS,           {{},            {},            1 * NS_PER_SEC,            new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}}, -        }; +        // ProcStats. +        {android::util::PROC_STATS, +         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}}, +        // Disk I/O stats per uid. +        {android::util::DISK_IO, +         {{2,3,4,5,6,7,8,9,10,11}, +          {}, +          3 * NS_PER_SEC, +          new StatsCompanionServicePuller(android::util::DISK_IO)}}, +};  StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {  } diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index f9f1b387279a..4bbcfd593366 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -92,7 +92,8 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT  LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,                     int32_t uid, -                   const std::map<int32_t, int64_t>& int_map, +                   const std::map<int32_t, int32_t>& int_map, +                   const std::map<int32_t, int64_t>& long_map,                     const std::map<int32_t, std::string>& string_map,                     const std::map<int32_t, float>& float_map) {      mLogdTimestampNs = wallClockTimestampNs; @@ -113,7 +114,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT          pos[1]++;      } -    for (const auto&itr : string_map) { +    for (const auto&itr : long_map) {          pos[2] = 1;          mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));          pos[2] = 3; @@ -122,7 +123,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT          pos[1]++;      } -    for (const auto&itr : float_map) { +    for (const auto&itr : string_map) {          pos[2] = 1;          mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));          pos[2] = 4; @@ -130,12 +131,142 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT          mValues.back().mField.decorateLastPos(2);          pos[1]++;      } + +    for (const auto&itr : float_map) { +        pos[2] = 1; +        mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first))); +        pos[2] = 5; +        mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second))); +        mValues.back().mField.decorateLastPos(2); +        pos[1]++; +    }      if (!mValues.empty()) {          mValues.back().mField.decorateLastPos(1);          mValues.at(mValues.size() - 2).mField.decorateLastPos(1);      }  } +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const SpeakerImpedance& speakerImpedance) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::SPEAKER_IMPEDANCE_REPORTED; + +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(1)), Value(speakerImpedance.speakerLocation))); +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(2)), Value(speakerImpedance.milliOhms))); +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const HardwareFailed& hardwareFailed) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::HARDWARE_FAILED; + +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), +                                 Value(int32_t(hardwareFailed.hardwareType)))); +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(2)), Value(hardwareFailed.hardwareLocation))); +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(3)), Value(int32_t(hardwareFailed.errorCode)))); +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const PhysicalDropDetected& physicalDropDetected) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::PHYSICAL_DROP_DETECTED; + +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), +                                 Value(int32_t(physicalDropDetected.confidencePctg)))); +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(2)), Value(physicalDropDetected.accelPeak))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), +                                 Value(physicalDropDetected.freefallDuration))); +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const ChargeCycles& chargeCycles) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::CHARGE_CYCLES_REPORTED; + +    for (size_t i = 0; i < chargeCycles.cycleBucket.size(); i++) { +        mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 1)), +                                     Value(chargeCycles.cycleBucket[i]))); +    } + +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::BATTERY_HEALTH_SNAPSHOT; + +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), +                                 Value(int32_t(batteryHealthSnapshotArgs.type)))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), +                                 Value(batteryHealthSnapshotArgs.temperatureDeciC))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), +                                 Value(batteryHealthSnapshotArgs.voltageMicroV))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), +                                 Value(batteryHealthSnapshotArgs.currentMicroA))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(5)), +                                 Value(batteryHealthSnapshotArgs.openCircuitVoltageMicroV))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), +                                 Value(batteryHealthSnapshotArgs.resistanceMicroOhm))); +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), +                                 Value(batteryHealthSnapshotArgs.levelPercent))); + +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, const SlowIo& slowIo) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::SLOW_IO; + +    int pos[] = {1}; +    mValues.push_back( +            FieldValue(Field(mTagId, getSimpleField(1)), Value(int32_t(slowIo.operation)))); +    pos[0]++; +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(slowIo.count))); + +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                   const BatteryCausedShutdown& batteryCausedShutdown) { +    mLogdTimestampNs = wallClockTimestampNs; +    mElapsedTimestampNs = elapsedTimestampNs; +    mTagId = android::util::BATTERY_CAUSED_SHUTDOWN; + +    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), +                                 Value(batteryCausedShutdown.voltageMicroV))); + +    if (!mValues.empty()) { +        mValues.back().mField.decorateLastPos(1); +    } +} +  LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {      mLogdTimestampNs = timestampNs;      mTagId = tagId; @@ -213,9 +344,8 @@ bool LogEvent::write(float value) {      return false;  } - - -bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map, +bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map, +                                  const std::map<int32_t, int64_t>& long_map,                                    const std::map<int32_t, std::string>& string_map,                                    const std::map<int32_t, float>& float_map) {      if (mContext) { @@ -233,6 +363,17 @@ bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,               }           } +         for (const auto& itr : long_map) { +             if (android_log_write_list_begin(mContext) < 0) { +                return false; +             } +             write(itr.first); +             write(itr.second); +             if (android_log_write_list_end(mContext) < 0) { +                return false; +             } +         } +           for (const auto& itr : string_map) {               if (android_log_write_list_begin(mContext) < 0) {                  return false; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 9ef0bf469c14..c7e2a8c5ca21 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -18,6 +18,7 @@  #include "FieldValue.h" +#include <android/frameworks/stats/1.0/types.h>  #include <android/os/StatsLogEventWrapper.h>  #include <android/util/ProtoOutputStream.h>  #include <log/log_event_list.h> @@ -28,6 +29,8 @@  #include <string>  #include <vector> +using namespace android::frameworks::stats::V1_0; +  namespace android {  namespace os {  namespace statsd { @@ -77,10 +80,32 @@ public:       */      explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,                        int32_t uid, -                      const std::map<int32_t, int64_t>& int_map, +                      const std::map<int32_t, int32_t>& int_map, +                      const std::map<int32_t, int64_t>& long_map,                        const std::map<int32_t, std::string>& string_map,                        const std::map<int32_t, float>& float_map); +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const SpeakerImpedance& speakerImpedance); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const HardwareFailed& hardwareFailed); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const PhysicalDropDetected& physicalDropDetected); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const ChargeCycles& chargeCycles); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const SlowIo& slowIo); + +    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, +                      const BatteryCausedShutdown& batteryCausedShutdown); +      ~LogEvent();      /** @@ -122,7 +147,8 @@ public:      bool write(float value);      bool write(const std::vector<AttributionNodeInternal>& nodes);      bool write(const AttributionNodeInternal& node); -    bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map, +    bool writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map, +                            const std::map<int32_t, int64_t>& long_map,                              const std::map<int32_t, std::string>& string_map,                              const std::map<int32_t, float>& float_map); diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 9002f0773aaf..a5dac0836238 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -25,6 +25,7 @@  #include <binder/IServiceManager.h>  #include <binder/ProcessState.h>  #include <binder/Status.h> +#include <hidl/HidlTransportSupport.h>  #include <utils/Looper.h>  #include <utils/StrongPointer.h> @@ -56,12 +57,21 @@ int main(int /*argc*/, char** /*argv*/) {      ps->giveThreadPoolName();      IPCThreadState::self()->disableBackgroundScheduling(true); +    ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/); +      // Create the service      sp<StatsService> service = new StatsService(looper);      if (defaultServiceManager()->addService(String16("stats"), service) != 0) { -        ALOGE("Failed to add service"); +        ALOGE("Failed to add service as AIDL service");          return -1;      } + +    auto ret = service->registerAsService(); +    if (ret != ::android::OK) { +        ALOGE("Failed to add service as HIDL service"); +        return 1; // or handle error +    } +      service->sayHiToStatsCompanion();      service->Startup(); diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index 9d9e5be9e165..dd3402dae2f8 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -781,7 +781,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,          if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {              for (const auto& condIt : whatIt->second) {                  const bool cond = dimensionKeysInCondition.find(condIt.first) != -                        dimensionKeysInCondition.end(); +                        dimensionKeysInCondition.end() && condition;                  handleStartEvent(MetricDimensionKey(dimensionInWhat, condIt.first),                      conditionKey, cond, event);                  dimensionKeysInCondition.erase(condIt.first); diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index 3cd49d722fea..1306a467e5c4 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -113,12 +113,12 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) {      for (const auto& matcher : mPushedMatchers) {          if (matchesSimple(*mUidMap, matcher, event)) { +            event.ToProto(mProto);              // First write the payload size.              size_t bufferSize = mProto.size();              write(mOutput, &bufferSize, sizeof(bufferSize));              // Then write the payload. -            event.ToProto(mProto);              mProto.flush(mOutput);              mProto.clear();              break; @@ -137,4 +137,4 @@ void ShellSubscriber::binderDied(const wp<IBinder>& who) {  }  // namespace statsd  }  // namespace os -}  // namespace android
\ No newline at end of file +}  // namespace android diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 6e3b04ce6b3b..d4907017dc6d 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -91,12 +91,16 @@ TEST(LogEventTest, TestLogParsing) {  TEST(LogEventTest, TestKeyValuePairsAtomParsing) {      LogEvent event1(83, 2000); -    std::map<int32_t, int64_t> int_map; +    std::map<int32_t, int32_t> int_map; +    std::map<int32_t, int64_t> long_map;      std::map<int32_t, std::string> string_map;      std::map<int32_t, float> float_map; -    int_map[11] = 123L; -    int_map[22] = 345L; +    int_map[11] = 123; +    int_map[22] = 345; + +    long_map[33] = 678L; +    long_map[44] = 890L;      string_map[1] = "test2";      string_map[2] = "test1"; @@ -104,12 +108,15 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {      float_map[111] = 2.2f;      float_map[222] = 1.1f; -    EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map)); +    EXPECT_TRUE(event1.writeKeyValuePairs(int_map, +                                          long_map, +                                          string_map, +                                          float_map));      event1.init();      EXPECT_EQ(83, event1.GetTagId());      const auto& items = event1.getValues(); -    EXPECT_EQ((size_t)12, items.size()); +    EXPECT_EQ((size_t)16, items.size());      const FieldValue& item0 = event1.getValues()[0];      EXPECT_EQ(0x2010101, item0.mField.getField()); @@ -118,8 +125,8 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {      const FieldValue& item1 = event1.getValues()[1];      EXPECT_EQ(0x2010182, item1.mField.getField()); -    EXPECT_EQ(Type::LONG, item1.mValue.getType()); -    EXPECT_EQ(123L, item1.mValue.long_value); +    EXPECT_EQ(Type::INT, item1.mValue.getType()); +    EXPECT_EQ(123, item1.mValue.int_value);      const FieldValue& item2 = event1.getValues()[2];      EXPECT_EQ(0x2010201, item2.mField.getField()); @@ -128,48 +135,68 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {      const FieldValue& item3 = event1.getValues()[3];      EXPECT_EQ(0x2010282, item3.mField.getField()); -    EXPECT_EQ(Type::LONG, item3.mValue.getType()); -    EXPECT_EQ(345L, item3.mValue.long_value); +    EXPECT_EQ(Type::INT, item3.mValue.getType()); +    EXPECT_EQ(345, item3.mValue.int_value);      const FieldValue& item4 = event1.getValues()[4];      EXPECT_EQ(0x2010301, item4.mField.getField());      EXPECT_EQ(Type::INT, item4.mValue.getType()); -    EXPECT_EQ(1, item4.mValue.int_value); +    EXPECT_EQ(33, item4.mValue.int_value);      const FieldValue& item5 = event1.getValues()[5]; -    EXPECT_EQ(0x2010383, item5.mField.getField()); -    EXPECT_EQ(Type::STRING, item5.mValue.getType()); -    EXPECT_EQ("test2", item5.mValue.str_value); +    EXPECT_EQ(0x2010382, item5.mField.getField()); +    EXPECT_EQ(Type::LONG, item5.mValue.getType()); +    EXPECT_EQ(678L, item5.mValue.int_value);      const FieldValue& item6 = event1.getValues()[6];      EXPECT_EQ(0x2010401, item6.mField.getField());      EXPECT_EQ(Type::INT, item6.mValue.getType()); -    EXPECT_EQ(2, item6.mValue.int_value); +    EXPECT_EQ(44, item6.mValue.int_value);      const FieldValue& item7 = event1.getValues()[7]; -    EXPECT_EQ(0x2010483, item7.mField.getField()); -    EXPECT_EQ(Type::STRING, item7.mValue.getType()); -    EXPECT_EQ("test1", item7.mValue.str_value); +    EXPECT_EQ(0x2010482, item7.mField.getField()); +    EXPECT_EQ(Type::LONG, item7.mValue.getType()); +    EXPECT_EQ(890L, item7.mValue.int_value);      const FieldValue& item8 = event1.getValues()[8];      EXPECT_EQ(0x2010501, item8.mField.getField());      EXPECT_EQ(Type::INT, item8.mValue.getType()); -    EXPECT_EQ(111, item8.mValue.int_value); +    EXPECT_EQ(1, item8.mValue.int_value);      const FieldValue& item9 = event1.getValues()[9]; -    EXPECT_EQ(0x2010584, item9.mField.getField()); -    EXPECT_EQ(Type::FLOAT, item9.mValue.getType()); -    EXPECT_EQ(2.2f, item9.mValue.float_value); +    EXPECT_EQ(0x2010583, item9.mField.getField()); +    EXPECT_EQ(Type::STRING, item9.mValue.getType()); +    EXPECT_EQ("test2", item9.mValue.str_value);      const FieldValue& item10 = event1.getValues()[10]; -    EXPECT_EQ(0x2018601, item10.mField.getField()); +    EXPECT_EQ(0x2010601, item10.mField.getField());      EXPECT_EQ(Type::INT, item10.mValue.getType()); -    EXPECT_EQ(222, item10.mValue.int_value); +    EXPECT_EQ(2, item10.mValue.int_value);      const FieldValue& item11 = event1.getValues()[11]; -    EXPECT_EQ(0x2018684, item11.mField.getField()); -    EXPECT_EQ(Type::FLOAT, item11.mValue.getType()); -    EXPECT_EQ(1.1f, item11.mValue.float_value); +    EXPECT_EQ(0x2010683, item11.mField.getField()); +    EXPECT_EQ(Type::STRING, item11.mValue.getType()); +    EXPECT_EQ("test1", item11.mValue.str_value); + +    const FieldValue& item12 = event1.getValues()[12]; +    EXPECT_EQ(0x2010701, item12.mField.getField()); +    EXPECT_EQ(Type::INT, item12.mValue.getType()); +    EXPECT_EQ(111, item12.mValue.int_value); + +    const FieldValue& item13 = event1.getValues()[13]; +    EXPECT_EQ(0x2010784, item13.mField.getField()); +    EXPECT_EQ(Type::FLOAT, item13.mValue.getType()); +    EXPECT_EQ(2.2f, item13.mValue.float_value); + +    const FieldValue& item14 = event1.getValues()[14]; +    EXPECT_EQ(0x2018801, item14.mField.getField()); +    EXPECT_EQ(Type::INT, item14.mValue.getType()); +    EXPECT_EQ(222, item14.mValue.int_value); + +    const FieldValue& item15 = event1.getValues()[15]; +    EXPECT_EQ(0x2018884, item15.mField.getField()); +    EXPECT_EQ(Type::FLOAT, item15.mValue.getType()); +    EXPECT_EQ(1.1f, item15.mValue.float_value);  }  TEST(LogEventTest, TestLogParsing2) { @@ -242,12 +269,16 @@ TEST(LogEventTest, TestLogParsing2) {  }  TEST(LogEventTest, TestKeyValuePairsEvent) { -    std::map<int32_t, int64_t> int_map; +    std::map<int32_t, int32_t> int_map; +    std::map<int32_t, int64_t> long_map;      std::map<int32_t, std::string> string_map;      std::map<int32_t, float> float_map; -    int_map[11] = 123L; -    int_map[22] = 345L; +    int_map[11] = 123; +    int_map[22] = 345; + +    long_map[33] = 678L; +    long_map[44] = 890L;      string_map[1] = "test2";      string_map[2] = "test1"; @@ -255,7 +286,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {      float_map[111] = 2.2f;      float_map[222] = 1.1f; -    LogEvent event1(83, 2000, 2001, 10001, int_map, string_map, float_map); +    LogEvent event1(83, 2000, 2001, 10001, int_map, long_map, string_map, float_map);      event1.init();      EXPECT_EQ(83, event1.GetTagId()); @@ -263,7 +294,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {      EXPECT_EQ((int64_t)2001, event1.GetElapsedTimestampNs());      const auto& items = event1.getValues(); -    EXPECT_EQ((size_t)13, items.size()); +    EXPECT_EQ((size_t)17, items.size());      const FieldValue& item0 = event1.getValues()[0];      EXPECT_EQ(0x00010000, item0.mField.getField()); @@ -277,8 +308,8 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {      const FieldValue& item2 = event1.getValues()[2];      EXPECT_EQ(0x2020182, item2.mField.getField()); -    EXPECT_EQ(Type::LONG, item2.mValue.getType()); -    EXPECT_EQ(123L, item2.mValue.long_value); +    EXPECT_EQ(Type::INT, item2.mValue.getType()); +    EXPECT_EQ(123, item2.mValue.int_value);      const FieldValue& item3 = event1.getValues()[3];      EXPECT_EQ(0x2020201, item3.mField.getField()); @@ -287,48 +318,68 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {      const FieldValue& item4 = event1.getValues()[4];      EXPECT_EQ(0x2020282, item4.mField.getField()); -    EXPECT_EQ(Type::LONG, item4.mValue.getType()); -    EXPECT_EQ(345L, item4.mValue.long_value); +    EXPECT_EQ(Type::INT, item4.mValue.getType()); +    EXPECT_EQ(345, item4.mValue.int_value);      const FieldValue& item5 = event1.getValues()[5];      EXPECT_EQ(0x2020301, item5.mField.getField());      EXPECT_EQ(Type::INT, item5.mValue.getType()); -    EXPECT_EQ(1, item5.mValue.int_value); +    EXPECT_EQ(33, item5.mValue.int_value);      const FieldValue& item6 = event1.getValues()[6]; -    EXPECT_EQ(0x2020383, item6.mField.getField()); -    EXPECT_EQ(Type::STRING, item6.mValue.getType()); -    EXPECT_EQ("test2", item6.mValue.str_value); +    EXPECT_EQ(0x2020382, item6.mField.getField()); +    EXPECT_EQ(Type::LONG, item6.mValue.getType()); +    EXPECT_EQ(678L, item6.mValue.long_value);      const FieldValue& item7 = event1.getValues()[7];      EXPECT_EQ(0x2020401, item7.mField.getField());      EXPECT_EQ(Type::INT, item7.mValue.getType()); -    EXPECT_EQ(2, item7.mValue.int_value); +    EXPECT_EQ(44, item7.mValue.int_value);      const FieldValue& item8 = event1.getValues()[8]; -    EXPECT_EQ(0x2020483, item8.mField.getField()); -    EXPECT_EQ(Type::STRING, item8.mValue.getType()); -    EXPECT_EQ("test1", item8.mValue.str_value); +    EXPECT_EQ(0x2020482, item8.mField.getField()); +    EXPECT_EQ(Type::LONG, item8.mValue.getType()); +    EXPECT_EQ(890L, item8.mValue.long_value);      const FieldValue& item9 = event1.getValues()[9];      EXPECT_EQ(0x2020501, item9.mField.getField());      EXPECT_EQ(Type::INT, item9.mValue.getType()); -    EXPECT_EQ(111, item9.mValue.int_value); +    EXPECT_EQ(1, item9.mValue.int_value);      const FieldValue& item10 = event1.getValues()[10]; -    EXPECT_EQ(0x2020584, item10.mField.getField()); -    EXPECT_EQ(Type::FLOAT, item10.mValue.getType()); -    EXPECT_EQ(2.2f, item10.mValue.float_value); +    EXPECT_EQ(0x2020583, item10.mField.getField()); +    EXPECT_EQ(Type::STRING, item10.mValue.getType()); +    EXPECT_EQ("test2", item10.mValue.str_value);      const FieldValue& item11 = event1.getValues()[11]; -    EXPECT_EQ(0x2028601, item11.mField.getField()); +    EXPECT_EQ(0x2020601, item11.mField.getField());      EXPECT_EQ(Type::INT, item11.mValue.getType()); -    EXPECT_EQ(222, item11.mValue.int_value); +    EXPECT_EQ(2, item11.mValue.int_value);      const FieldValue& item12 = event1.getValues()[12]; -    EXPECT_EQ(0x2028684, item12.mField.getField()); -    EXPECT_EQ(Type::FLOAT, item12.mValue.getType()); -    EXPECT_EQ(1.1f, item12.mValue.float_value); +    EXPECT_EQ(0x2020683, item12.mField.getField()); +    EXPECT_EQ(Type::STRING, item12.mValue.getType()); +    EXPECT_EQ("test1", item12.mValue.str_value); + +    const FieldValue& item13 = event1.getValues()[13]; +    EXPECT_EQ(0x2020701, item13.mField.getField()); +    EXPECT_EQ(Type::INT, item13.mValue.getType()); +    EXPECT_EQ(111, item13.mValue.int_value); + +    const FieldValue& item14 = event1.getValues()[14]; +    EXPECT_EQ(0x2020784, item14.mField.getField()); +    EXPECT_EQ(Type::FLOAT, item14.mValue.getType()); +    EXPECT_EQ(2.2f, item14.mValue.float_value); + +    const FieldValue& item15 = event1.getValues()[15]; +    EXPECT_EQ(0x2028801, item15.mField.getField()); +    EXPECT_EQ(Type::INT, item15.mValue.getType()); +    EXPECT_EQ(222, item15.mValue.int_value); + +    const FieldValue& item16 = event1.getValues()[16]; +    EXPECT_EQ(0x2028884, item16.mField.getField()); +    EXPECT_EQ(Type::FLOAT, item16.mValue.getType()); +    EXPECT_EQ(1.1f, item16.mValue.float_value);  } @@ -337,4 +388,4 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {  }  // namespace android  #else  GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif
\ No newline at end of file +#endif diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp index f03821432cc1..75bd40f67946 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp @@ -81,6 +81,34 @@ StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(  }  // namespace +/* + The following test has the following input. + +{ 10000000002 10000000002 (8)9999[I], [S], job0[S], 1[I],  } +{ 10000000010 10000000010 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  } +{ 10000000011 10000000011 (29)1[I],  } +{ 10000000040 10000000040 (29)2[I],  } +{ 10000000050 10000000050 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  } +{ 10000000101 10000000101 (8)9999[I], [S], job0[S], 0[I],  } +{ 10000000102 10000000102 (29)1[I],  } +{ 10000000200 10000000200 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  } +{ 10000000201 10000000201 (8)9999[I], [S], job2[S], 1[I],  } +{ 10000000400 10000000400 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 1[I],  } +{ 10000000401 10000000401 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  } +{ 10000000450 10000000450 (29)2[I],  } +{ 10000000500 10000000500 (8)9999[I], [S], job2[S], 0[I],  } +{ 10000000600 10000000600 (8)8888[I], [S], job2[S], 1[I],  } +{ 10000000650 10000000650 (29)1[I],  } +{ 309999999999 309999999999 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 0[I],  } +{ 310000000100 310000000100 (29)2[I],  } +{ 310000000300 310000000300 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  } +{ 310000000600 310000000600 (8)8888[I], [S], job1[S], 1[I],  } +{ 310000000640 310000000640 (29)1[I],  } +{ 310000000650 310000000650 (29)2[I],  } +{ 310000000700 310000000700 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  } +{ 310000000850 310000000850 (8)8888[I], [S], job2[S], 0[I],  } +{ 310000000900 310000000900 (8)8888[I], [S], job1[S], 0[I],  } +*/  TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {      for (const bool hashStringInReport : { true, false }) {          for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) { @@ -250,7 +278,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi                      EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);                      EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs); -                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 600); +                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 650);                      EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);                      EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs); @@ -269,7 +297,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi                              data.dimensions_in_condition(),                              android::util::SYNC_STATE_CHANGED, 333, "App2");                      EXPECT_EQ(data.bucket_info_size(), 2); -                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 600); +                    EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 650);                      EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);                      EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs); @@ -331,7 +359,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi                      EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs);                      EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201); -                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100); +                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 100);                      EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs);                      EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), @@ -353,7 +381,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi                      EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);                      EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs); -                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 110); +                    EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 110);                      EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),                                bucketStartTimeNs + bucketSizeNs);                      EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp new file mode 100644 index 000000000000..b380b03e28d0 --- /dev/null +++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp @@ -0,0 +1,136 @@ +// 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. + +#include <gtest/gtest.h> + +#include <unistd.h> +#include "frameworks/base/cmds/statsd/src/atoms.pb.h" +#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h" +#include "src/shell/ShellSubscriber.h" +#include "tests/metrics/metrics_test_helper.h" + +#include <stdio.h> +#include <vector> + +using namespace android::os::statsd; +using android::sp; +using std::vector; +using testing::NaggyMock; + +#ifdef __ANDROID__ + +class MyResultReceiver : public BnResultReceiver { +public: +    Mutex mMutex; +    Condition mCondition; +    bool mHaveResult = false; +    int32_t mResult = 0; + +    virtual void send(int32_t resultCode) { +        AutoMutex _l(mMutex); +        mResult = resultCode; +        mHaveResult = true; +        mCondition.signal(); +    } + +    int32_t waitForResult() { +        AutoMutex _l(mMutex); +        mCondition.waitRelative(mMutex, 1000000000); +        return mResult; +    } +}; + +TEST(ShellSubscriberTest, testPushedSubscription) { +    // set up 2 pipes for read/write config and data +    int fds_config[2]; +    ASSERT_EQ(0, pipe(fds_config)); + +    int fds_data[2]; +    ASSERT_EQ(0, pipe(fds_data)); + +    // create a simple config to get screen events +    ShellSubscription config; +    config.add_pushed()->set_atom_id(29); + +    size_t bufferSize = config.ByteSize(); + +    // write the config to pipe, first write size of the config +    vector<uint8_t> size_buffer(sizeof(bufferSize)); +    std::memcpy(size_buffer.data(), &bufferSize, sizeof(bufferSize)); +    write(fds_config[1], &bufferSize, sizeof(bufferSize)); +    // then write config itself +    vector<uint8_t> buffer(bufferSize); +    config.SerializeToArray(&buffer[0], bufferSize); +    write(fds_config[1], buffer.data(), bufferSize); +    close(fds_config[1]); + +    // create a shell subscriber. +    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); +    sp<ShellSubscriber> shellClient = new ShellSubscriber(uidMap); +    sp<MyResultReceiver> resultReceiver = new MyResultReceiver(); + +    LogEvent event1(29, 1000); +    event1.write(2); +    event1.init(); + +    // mimic a binder thread that a shell subscriber runs on. it would block. +    std::thread reader([&resultReceiver, &fds_config, &fds_data, &shellClient] { +        shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver); +    }); +    reader.detach(); + +    // let the shell subscriber to receive the config from pipe. +    std::this_thread::sleep_for(100ms); + +    // send a log event that matches the config. +    std::thread log_reader([&shellClient, &event1] { shellClient->onLogEvent(event1); }); +    log_reader.detach(); + +    if (log_reader.joinable()) { +        log_reader.join(); +    } + +    // wait for the data to be written. +    std::this_thread::sleep_for(100ms); + +    // this is the expected screen event atom. +    Atom atom; +    atom.mutable_screen_state_changed()->set_state( +            ::android::view::DisplayStateEnum::DISPLAY_STATE_ON); + +    int atom_size = atom.ByteSize(); + +    // now read from the pipe. firstly read the atom size. +    size_t dataSize = 0; +    EXPECT_EQ((int)sizeof(dataSize), read(fds_data[0], &dataSize, sizeof(dataSize))); +    EXPECT_EQ(atom_size, (int)dataSize); + +    // then read that much data which is the atom in proto binary format +    vector<uint8_t> dataBuffer(dataSize); +    EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize)); + +    // make sure the received bytes can be parsed to an atom +    Atom receivedAtom; +    EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0); + +    // serialze the expected atom to bytes. and compare. to make sure they are the same. +    vector<uint8_t> atomBuffer(atom_size); +    atom.SerializeToArray(&atomBuffer[0], atom_size); +    EXPECT_EQ(atomBuffer, dataBuffer); +    close(fds_data[0]); +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 1ad8e7e56330..6af34f9151b9 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -2075,27 +2075,20 @@ Lcom/android/internal/telephony/ISub;->getDefaultDataSubId()I  Lcom/android/internal/telephony/ISub;->getDefaultSubId()I  Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V  Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z  Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;  Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z  Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;  Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;  Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String; -Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_answerRingingCall:I  Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I  Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I -Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I  Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I -Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V  Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V  Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V  Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z  Lcom/android/internal/telephony/ITelephony;->disableLocationUpdates()V  Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z  Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V -Lcom/android/internal/telephony/ITelephony;->endCall()Z -Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z  Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I  Lcom/android/internal/telephony/ITelephony;->getCallState()I  Lcom/android/internal/telephony/ITelephony;->getDataActivity()I @@ -2107,12 +2100,8 @@ Lcom/android/internal/telephony/ITelephony;->handlePinMmiForSubscriber(ILjava/la  Lcom/android/internal/telephony/ITelephony;->hasIccCard()Z  Lcom/android/internal/telephony/ITelephony;->iccCloseLogicalChannel(II)Z  Lcom/android/internal/telephony/ITelephony;->iccTransmitApduLogicalChannel(IIIIIIILjava/lang/String;)Ljava/lang/String; -Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z -Lcom/android/internal/telephony/ITelephony;->isIdleForSubscriber(ILjava/lang/String;)Z  Lcom/android/internal/telephony/ITelephony;->isRadioOnForSubscriber(ILjava/lang/String;)Z -Lcom/android/internal/telephony/ITelephony;->isRinging(Ljava/lang/String;)Z  Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z -Lcom/android/internal/telephony/ITelephony;->silenceRinger()V  Lcom/android/internal/telephony/ITelephony;->supplyPin(Ljava/lang/String;)Z  Lcom/android/internal/telephony/ITelephony;->toggleRadioOnOff()V  Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V diff --git a/config/preloaded-classes b/config/preloaded-classes index d93befdf5143..56ca98ff9888 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -1022,6 +1022,7 @@ android.graphics.-$$Lambda$ColorSpace$Rgb$b9VGKuNnse0bbguR9jbOM_wK2Ac  android.graphics.-$$Lambda$ColorSpace$Rgb$bWzafC8vMHNuVmRuTUPEFUMlfuY  android.graphics.-$$Lambda$ColorSpace$S2rlqJvkXGTpUF6mZhvkElds8JE  android.graphics.BaseCanvas +android.graphics.BaseRecordingCanvas  android.graphics.Bitmap  android.graphics.Bitmap$1  android.graphics.Bitmap$2 @@ -3303,7 +3304,6 @@ android.view.OrientationEventListener  android.view.OrientationEventListener$SensorEventListenerImpl  android.view.PointerIcon  android.view.PointerIcon$1 -android.view.RecordingCanvas  android.view.RenderNode  android.view.RenderNode$NoImagePreloadHolder  android.view.RenderNodeAnimator diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2ee266de4c77..482ef2d1a6fd 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -394,7 +394,7 @@ import java.util.List;   *         <td>The final call you receive before your   *             activity is destroyed.  This can happen either because the   *             activity is finishing (someone called {@link Activity#finish} on - *             it, or because the system is temporarily destroying this + *             it), or because the system is temporarily destroying this   *             instance of the activity to save space.  You can distinguish   *             between these two scenarios with the {@link   *             Activity#isFinishing} method.</td> @@ -1588,11 +1588,13 @@ public class Activity extends ContextThemeWrapper       * @param outState The bundle to save the state to.       */      final void performSaveInstanceState(@NonNull Bundle outState) { +        getApplication().dispatchActivityPreSaveInstanceState(this, outState);          onSaveInstanceState(outState);          saveManagedDialogs(outState);          mActivityTransitionState.saveState(outState);          storeHasCurrentPermissionRequest(outState);          if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState); +        getApplication().dispatchActivityPostSaveInstanceState(this, outState);      }      /** @@ -1606,11 +1608,13 @@ public class Activity extends ContextThemeWrapper       */      final void performSaveInstanceState(@NonNull Bundle outState,              @NonNull PersistableBundle outPersistentState) { +        getApplication().dispatchActivityPreSaveInstanceState(this, outState);          onSaveInstanceState(outState, outPersistentState);          saveManagedDialogs(outState);          storeHasCurrentPermissionRequest(outState);          if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +                  ", " + outPersistentState); +        getApplication().dispatchActivityPostSaveInstanceState(this, outState);      }      /** @@ -1981,7 +1985,7 @@ public class Activity extends ContextThemeWrapper      /**       * Perform any final cleanup before an activity is destroyed.  This can       * happen either because the activity is finishing (someone called -     * {@link #finish} on it, or because the system is temporarily destroying +     * {@link #finish} on it), or because the system is temporarily destroying       * this instance of the activity to save space.  You can distinguish       * between these two scenarios with the {@link #isFinishing} method.       * @@ -7195,6 +7199,7 @@ public class Activity extends ContextThemeWrapper      @UnsupportedAppUsage      final void performCreate(Bundle icicle, PersistableBundle persistentState) { +        getApplication().dispatchActivityPreCreated(this, icicle);          mCanEnterPictureInPicture = true;          restoreHasCurrentPermissionRequest(icicle);          if (persistentState != null) { @@ -7209,6 +7214,7 @@ public class Activity extends ContextThemeWrapper                  com.android.internal.R.styleable.Window_windowNoDisplay, false);          mFragments.dispatchActivityCreated();          mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); +        getApplication().dispatchActivityPostCreated(this, icicle);      }      final void performNewIntent(@NonNull Intent intent) { @@ -7217,6 +7223,7 @@ public class Activity extends ContextThemeWrapper      }      final void performStart(String reason) { +        getApplication().dispatchActivityPreStarted(this);          mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());          mFragments.noteStateNotSaved();          mCalled = false; @@ -7284,6 +7291,7 @@ public class Activity extends ContextThemeWrapper          }          mActivityTransitionState.enterReady(this); +        getApplication().dispatchActivityPostStarted(this);      }      /** @@ -7338,6 +7346,7 @@ public class Activity extends ContextThemeWrapper      }      final void performResume(boolean followedByPause, String reason) { +        getApplication().dispatchActivityPreResumed(this);          performRestart(true /* start */, reason);          mFragments.execPendingActions(); @@ -7387,9 +7396,11 @@ public class Activity extends ContextThemeWrapper                  "Activity " + mComponent.toShortString() +                  " did not call through to super.onPostResume()");          } +        getApplication().dispatchActivityPostResumed(this);      }      final void performPause() { +        getApplication().dispatchActivityPrePaused(this);          mDoReportFullyDrawn = false;          mFragments.dispatchPause();          mCalled = false; @@ -7402,6 +7413,7 @@ public class Activity extends ContextThemeWrapper                      "Activity " + mComponent.toShortString() +                      " did not call through to super.onPause()");          } +        getApplication().dispatchActivityPostPaused(this);      }      final void performUserLeaving() { @@ -7417,6 +7429,7 @@ public class Activity extends ContextThemeWrapper          mCanEnterPictureInPicture = false;          if (!mStopped) { +            getApplication().dispatchActivityPreStopped(this);              if (mWindow != null) {                  mWindow.closeAllPanels();              } @@ -7451,11 +7464,13 @@ public class Activity extends ContextThemeWrapper              }              mStopped = true; +            getApplication().dispatchActivityPostStopped(this);          }          mResumed = false;      }      final void performDestroy() { +        getApplication().dispatchActivityPreDestroyed(this);          mDestroyed = true;          mWindow.destroy();          mFragments.dispatchDestroy(); @@ -7465,6 +7480,7 @@ public class Activity extends ContextThemeWrapper          if (mVoiceInteractor != null) {              mVoiceInteractor.detachActivity();          } +        getApplication().dispatchActivityPostDestroyed(this);      }      final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index be1f2dbc8e4f..294a3ec73efd 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -19,11 +19,14 @@ package android.app;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.content.ComponentName; +import android.content.IIntentReceiver;  import android.content.IIntentSender;  import android.content.Intent;  import android.content.pm.ApplicationInfo;  import android.content.pm.UserInfo; +import android.os.Bundle;  import android.os.IBinder; +import android.os.TransactionTooLargeException;  import android.view.RemoteAnimationAdapter;  import java.util.ArrayList; @@ -232,4 +235,14 @@ public abstract class ActivityManagerInternal {      public abstract void setBooted(boolean booted);      public abstract boolean isBooted();      public abstract void finishBooting(); + +    public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, +            long duration, String tag); +    public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent, +            String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, +            Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, +            boolean sticky, int userId); +    public abstract ComponentName startServiceInPackage(int uid, Intent service, +            String resolvedType, boolean fgRequired, String callingPackage, int userId) +            throws TransactionTooLargeException;  } diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 68b745d54bc0..e12942f248d4 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -65,13 +65,144 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      public LoadedApk mLoadedApk;      public interface ActivityLifecycleCallbacks { + +        /** +         * Called as the first step of the Activity being created. This is always called before +         * {@link Activity#onCreate}. +         */ +        default void onActivityPreCreated(@NonNull Activity activity, +                @Nullable Bundle savedInstanceState) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onCreate super.onCreate()}. +         */          void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState); + +        /** +         * Called as the last step of the Activity being created. This is always called after +         * {@link Activity#onCreate}. +         */ +        default void onActivityPostCreated(@NonNull Activity activity, +                @Nullable Bundle savedInstanceState) { +        } + +        /** +         * Called as the first step of the Activity being started. This is always called before +         * {@link Activity#onStart}. +         */ +        default void onActivityPreStarted(@NonNull Activity activity) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onStart super.onStart()}. +         */          void onActivityStarted(@NonNull Activity activity); + +        /** +         * Called as the last step of the Activity being started. This is always called after +         * {@link Activity#onStart}. +         */ +        default void onActivityPostStarted(@NonNull Activity activity) { +        } + +        /** +         * Called as the first step of the Activity being resumed. This is always called before +         * {@link Activity#onResume}. +         */ +        default void onActivityPreResumed(@NonNull Activity activity) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onResume super.onResume()}. +         */          void onActivityResumed(@NonNull Activity activity); + +        /** +         * Called as the last step of the Activity being resumed. This is always called after +         * {@link Activity#onResume} and {@link Activity#onPostResume}. +         */ +        default void onActivityPostResumed(@NonNull Activity activity) { +        } + +        /** +         * Called as the first step of the Activity being paused. This is always called before +         * {@link Activity#onPause}. +         */ +        default void onActivityPrePaused(@NonNull Activity activity) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onPause super.onPause()}. +         */          void onActivityPaused(@NonNull Activity activity); + +        /** +         * Called as the last step of the Activity being paused. This is always called after +         * {@link Activity#onPause}. +         */ +        default void onActivityPostPaused(@NonNull Activity activity) { +        } + +        /** +         * Called as the first step of the Activity being stopped. This is always called before +         * {@link Activity#onStop}. +         */ +        default void onActivityPreStopped(@NonNull Activity activity) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onStop super.onStop()}. +         */          void onActivityStopped(@NonNull Activity activity); + +        /** +         * Called as the last step of the Activity being stopped. This is always called after +         * {@link Activity#onStop}. +         */ +        default void onActivityPostStopped(@NonNull Activity activity) { +        } + +        /** +         * Called as the first step of the Activity saving its instance state. This is always +         * called before {@link Activity#onSaveInstanceState}. +         */ +        default void onActivityPreSaveInstanceState(@NonNull Activity activity, +                @NonNull Bundle outState) { +        } + +        /** +         * Called when the Activity calls +         * {@link Activity#onSaveInstanceState super.onSaveInstanceState()}. +         */          void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState); + +        /** +         * Called as the last step of the Activity saving its instance state. This is always +         * called after{@link Activity#onSaveInstanceState}. +         */ +        default void onActivityPostSaveInstanceState(@NonNull Activity activity, +                @NonNull Bundle outState) { +        } + +        /** +         * Called as the first step of the Activity being destroyed. This is always called before +         * {@link Activity#onDestroy}. +         */ +        default void onActivityPreDestroyed(@NonNull Activity activity) { +        } + +        /** +         * Called when the Activity calls {@link Activity#onDestroy super.onDestroy()}. +         */          void onActivityDestroyed(@NonNull Activity activity); + +        /** +         * Called as the last step of the Activity being destroyed. This is always called after +         * {@link Activity#onDestroy}. +         */ +        default void onActivityPostDestroyed(@NonNull Activity activity) { +        }      }      /** @@ -222,6 +353,18 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPreCreated(@NonNull Activity activity, +            @Nullable Bundle savedInstanceState) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreCreated(activity, +                        savedInstanceState); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityCreated(@NonNull Activity activity,              @Nullable Bundle savedInstanceState) {          Object[] callbacks = collectActivityLifecycleCallbacks(); @@ -234,6 +377,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostCreated(@NonNull Activity activity, +            @Nullable Bundle savedInstanceState) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(activity, +                        savedInstanceState); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPreStarted(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStarted(activity); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityStarted(@NonNull Activity activity) {          Object[] callbacks = collectActivityLifecycleCallbacks();          if (callbacks != null) { @@ -244,6 +409,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostStarted(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStarted(activity); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPreResumed(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreResumed(activity); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityResumed(@NonNull Activity activity) {          Object[] callbacks = collectActivityLifecycleCallbacks();          if (callbacks != null) { @@ -254,6 +439,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostResumed(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostResumed(activity); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPrePaused(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPrePaused(activity); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityPaused(@NonNull Activity activity) {          Object[] callbacks = collectActivityLifecycleCallbacks();          if (callbacks != null) { @@ -264,6 +469,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostPaused(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostPaused(activity); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPreStopped(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStopped(activity); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityStopped(@NonNull Activity activity) {          Object[] callbacks = collectActivityLifecycleCallbacks();          if (callbacks != null) { @@ -274,6 +499,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostStopped(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStopped(activity); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPreSaveInstanceState(@NonNull Activity activity, +            @NonNull Bundle outState) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreSaveInstanceState( +                        activity, outState); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivitySaveInstanceState(@NonNull Activity activity,              @NonNull Bundle outState) {          Object[] callbacks = collectActivityLifecycleCallbacks(); @@ -286,6 +533,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {      }      @UnsupportedAppUsage +        /* package */ void dispatchActivityPostSaveInstanceState(@NonNull Activity activity, +            @NonNull Bundle outState) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostSaveInstanceState( +                        activity, outState); +            } +        } +    } + +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPreDestroyed(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreDestroyed(activity); +            } +        } +    } + +    @UnsupportedAppUsage      /* package */ void dispatchActivityDestroyed(@NonNull Activity activity) {          Object[] callbacks = collectActivityLifecycleCallbacks();          if (callbacks != null) { @@ -295,6 +564,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {          }      } +    @UnsupportedAppUsage +        /* package */ void dispatchActivityPostDestroyed(@NonNull Activity activity) { +        Object[] callbacks = collectActivityLifecycleCallbacks(); +        if (callbacks != null) { +            for (int i = 0; i < callbacks.length; i++) { +                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostDestroyed(activity); +            } +        } +    } +      private Object[] collectComponentCallbacks() {          Object[] callbacks = null;          synchronized (mComponentCallbacks) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/core/java/android/app/ISmsAppService.aidl index c50d6d62d6e9..1ac2ec6b1c41 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java +++ b/core/java/android/app/ISmsAppService.aidl @@ -1,5 +1,5 @@  /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -11,15 +11,13 @@   * 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 + * limitations under the License.   */ -package com.android.systemui.stackdivider.events; - -import com.android.systemui.recents.events.EventBus; +package android.app;  /** - * Sent when the divider isn't draging anymore. + * @hide   */ -public class StoppedDragingEvent extends EventBus.Event { +interface ISmsAppService {  } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 3638bc48d2b5..81df447816d1 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4440,7 +4440,7 @@ public class Notification implements Parcelable          }          private CharSequence processTextSpans(CharSequence text) { -            if (hasForegroundColor()) { +            if (hasForegroundColor() || mInNightMode) {                  return ContrastColorUtil.clearColorSpans(text);              }              return text; diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java index e0aed16b8abf..9bfdae0d8c03 100644 --- a/core/java/android/app/ProcessMemoryState.java +++ b/core/java/android/app/ProcessMemoryState.java @@ -32,10 +32,11 @@ public final class ProcessMemoryState implements Parcelable {      public final long rssInBytes;      public final long cacheInBytes;      public final long swapInBytes; +    public final long rssHighWatermarkInBytes;      public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,                                long pgmajfault, long rssInBytes, long cacheInBytes, -                              long swapInBytes) { +                              long swapInBytes, long rssHighWatermarkInBytes) {          this.uid = uid;          this.processName = processName;          this.oomScore = oomScore; @@ -44,6 +45,7 @@ public final class ProcessMemoryState implements Parcelable {          this.rssInBytes = rssInBytes;          this.cacheInBytes = cacheInBytes;          this.swapInBytes = swapInBytes; +        this.rssHighWatermarkInBytes = rssHighWatermarkInBytes;      }      private ProcessMemoryState(Parcel in) { @@ -55,6 +57,7 @@ public final class ProcessMemoryState implements Parcelable {          rssInBytes = in.readLong();          cacheInBytes = in.readLong();          swapInBytes = in.readLong(); +        rssHighWatermarkInBytes = in.readLong();      }      public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() { @@ -84,5 +87,6 @@ public final class ProcessMemoryState implements Parcelable {          parcel.writeLong(rssInBytes);          parcel.writeLong(cacheInBytes);          parcel.writeLong(swapInBytes); +        parcel.writeLong(rssHighWatermarkInBytes);      }  } diff --git a/core/java/android/app/SmsAppService.java b/core/java/android/app/SmsAppService.java new file mode 100644 index 000000000000..3f2b025016df --- /dev/null +++ b/core/java/android/app/SmsAppService.java @@ -0,0 +1,57 @@ +/* + * 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.app; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.IBinder; + +/** + * If the default SMS app has a service that extends this class, the system always tries to bind + * it so that the process is always running, which allows the app to have a persistent connection + * to the server. + * + * <p>The service must have {@link android.telephony.TelephonyManager#ACTION_SMS_APP_SERVICE} + * action in the intent handler, and be protected with + * {@link android.Manifest.permission#BIND_SMS_APP_SERVICE}. However the service does not have to + * be exported. + * + * <p>Apps can use + * {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)} + * to disable/enable the service. Apps should use it to disable the service when it no longer needs + * to be running. + * + * <p>When the owner process crashes, the service will be re-bound automatically after a + * back-off. + * + * <p>Note the process may still be killed if the system is under heavy memory pressure, in which + * case the process will be re-started later. + */ +public class SmsAppService extends Service { +    private final ISmsAppService mImpl; + +    public SmsAppService() { +        mImpl = new ISmsAppServiceImpl(); +    } + +    @Override +    public final IBinder onBind(Intent intent) { +        return mImpl.asBinder(); +    } + +    private class ISmsAppServiceImpl extends ISmsAppService.Stub { +    } +} diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 2718bfacb618..bf3d885cd9c9 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -17,6 +17,7 @@  package android.app;  import android.annotation.IntDef; +import android.annotation.Nullable;  import android.annotation.SystemService;  import android.annotation.UnsupportedAppUsage;  import android.content.Context; @@ -208,10 +209,11 @@ public class StatusBarManager {      }      /** -     * Expand the settings panel and open a subPanel, pass null to just open the settings panel. +     * Expand the settings panel and open a subPanel. If the subpanel is null or does not have a +     * corresponding tile, the QS panel is simply expanded       */      @UnsupportedAppUsage -    public void expandSettingsPanel(String subPanel) { +    public void expandSettingsPanel(@Nullable String subPanel) {          try {              final IStatusBarService svc = getService();              if (svc != null) { diff --git a/core/java/android/app/WaitResult.java b/core/java/android/app/WaitResult.java index 898d0cabee3e..5baf2e22bc31 100644 --- a/core/java/android/app/WaitResult.java +++ b/core/java/android/app/WaitResult.java @@ -28,10 +28,10 @@ import java.io.PrintWriter;   * @hide   */  public class WaitResult implements Parcelable { +    public static final int INVALID_DELAY = -1;      public int result;      public boolean timeout;      public ComponentName who; -    public long thisTime;      public long totalTime;      public WaitResult() { @@ -47,7 +47,6 @@ public class WaitResult implements Parcelable {          dest.writeInt(result);          dest.writeInt(timeout ? 1 : 0);          ComponentName.writeToParcel(who, dest); -        dest.writeLong(thisTime);          dest.writeLong(totalTime);      } @@ -68,7 +67,6 @@ public class WaitResult implements Parcelable {          result = source.readInt();          timeout = source.readInt() != 0;          who = ComponentName.readFromParcel(source); -        thisTime = source.readLong();          totalTime = source.readLong();      } @@ -77,7 +75,6 @@ public class WaitResult implements Parcelable {          pw.println(prefix + "  result=" + result);          pw.println(prefix + "  timeout=" + timeout);          pw.println(prefix + "  who=" + who); -        pw.println(prefix + "  thisTime=" + thisTime);          pw.println(prefix + "  totalTime=" + totalTime);      }  }
\ No newline at end of file diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index e6fb5dc02ce3..096c7aa44446 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -28,9 +28,13 @@ import android.content.res.Configuration;  import android.graphics.Rect;  import android.os.Parcel;  import android.os.Parcelable; +import android.util.proto.ProtoInputStream;  import android.util.proto.ProtoOutputStream; +import android.util.proto.WireTypeMismatchException;  import android.view.DisplayInfo; +import java.io.IOException; +  /**   * Class that contains windowing configuration/state for other objects that contain windows directly   * or indirectly. E.g. Activities, Task, Displays, ... @@ -511,6 +515,38 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu      }      /** +     * Read from a protocol buffer input stream. +     * Protocol buffer message definition at {@link android.app.WindowConfigurationProto} +     * +     * @param proto   Stream to read the WindowConfiguration object from. +     * @param fieldId Field Id of the WindowConfiguration as defined in the parent message +     * @hide +     */ +    public void readFromProto(ProtoInputStream proto, long fieldId) +            throws IOException, WireTypeMismatchException { +        final long token = proto.start(fieldId); +        try { +            while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +                switch (proto.getFieldNumber()) { +                    case (int) APP_BOUNDS: +                        mAppBounds = new Rect(); +                        mAppBounds.readFromProto(proto, APP_BOUNDS); +                        break; +                    case (int) WINDOWING_MODE: +                        mWindowingMode = proto.readInt(WINDOWING_MODE); +                        break; +                    case (int) ACTIVITY_TYPE: +                        mActivityType = proto.readInt(ACTIVITY_TYPE); +                        break; +                } +            } +        } finally { +            // Let caller handle any exceptions +            proto.end(token); +        } +    } + +    /**       * Returns true if the activities associated with this window configuration display a shadow       * around their border.       * @hide diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index fc67c10e7e5e..1839263af5bf 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -7404,6 +7404,10 @@ public class DevicePolicyManager {       * If any app targeting {@link android.os.Build.VERSION_CODES#O} or higher calls this method       * with {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS},       * an {@link UnsupportedOperationException} is thrown. +     * +     * Starting from Android Q, the device and profile owner can also call +     * {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY} to restrict unknown sources for +     * all users.       * </strong>       *       * @param admin Which {@link DeviceAdminReceiver} this request is associated with. diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 9f22ad193e42..308b39efc3b1 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -165,6 +165,12 @@ public final class UsageEvents implements Parcelable {           */          public static final int KEYGUARD_HIDDEN = 18; +        /** +         * Keep in sync with the greatest event type value. +         * @hide +         */ +        public static final int MAX_EVENT_TYPE = 18; +          /** @hide */          public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; @@ -176,6 +182,12 @@ public final class UsageEvents implements Parcelable {          public @interface EventFlags {}          /** +         * Bitwise OR all valid flag constants to create this constant. +         * @hide +         */ +        public static final int VALID_FLAG_BITS = FLAG_IS_PACKAGE_INSTANT_APP; + +        /**           * {@hide}           */          @UnsupportedAppUsage diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 8d9533e09cbf..a64eead04c6f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -331,6 +331,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {              for (int i = 0; i < numOperations; i++) {                  ContentProviderOperation operation = operations.get(i);                  Uri uri = operation.getUri(); +                userIds[i] = getUserIdFromUri(uri);                  uri = validateIncomingUri(uri);                  uri = maybeGetUriWithoutUserId(uri);                  // Rebuild operation if we changed the Uri above diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index caaf4af247e9..d71157459fc8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4311,6 +4311,12 @@ public abstract class Context {      public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";      /** +     * Binder service name for {@link AppBindingService}. +     * @hide +     */ +    public static final String APP_BINDING_SERVICE = "app_binding"; + +    /**       * Determine whether the given permission is allowed for a particular       * process and user ID running in the system.       * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a15711f5da50..3032d164ef46 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1170,6 +1170,14 @@ public abstract class PackageManager {      public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27;      /** +     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS} +     * if the new package requires at least one split and it was not provided. +     * +     * @hide +     */ +    public static final int INSTALL_FAILED_MISSING_SPLIT = -28; + +    /**       * Installation parse return code: this is passed in the       * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser was given a path that is not a       * file, or does not end with the expected '.apk' extension. @@ -5927,8 +5935,8 @@ public abstract class PackageManager {              case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";              case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";              case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED"; -            case INSTALL_FAILED_BAD_DEX_METADATA: -                return "INSTALL_FAILED_BAD_DEX_METADATA"; +            case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA"; +            case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";              default: return Integer.toString(status);          }      } @@ -5979,6 +5987,7 @@ public abstract class PackageManager {              case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;              case INSTALL_FAILED_NO_MATCHING_ABIS: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;              case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; +            case INSTALL_FAILED_MISSING_SPLIT: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;              default: return PackageInstaller.STATUS_FAILURE;          }      } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 1fa5190ef8df..f5431caaf319 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -452,10 +452,12 @@ public class PackageParser {          public final boolean use32bitAbi;          public final boolean extractNativeLibs;          public final boolean isolatedSplits; +        public final boolean isSplitRequired;          public ApkLite(String codePath, String packageName, String splitName,                  boolean isFeatureSplit, -                String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor, +                String configForSplit, String usesSplitName, boolean isSplitRequired, +                int versionCode, int versionCodeMajor,                  int revisionCode, int installLocation, List<VerifierInfo> verifiers,                  SigningDetails signingDetails, boolean coreApp,                  boolean debuggable, boolean multiArch, boolean use32bitAbi, @@ -478,6 +480,7 @@ public class PackageParser {              this.use32bitAbi = use32bitAbi;              this.extractNativeLibs = extractNativeLibs;              this.isolatedSplits = isolatedSplits; +            this.isSplitRequired = isSplitRequired;          }          public long getLongVersionCode() { @@ -1695,6 +1698,7 @@ public class PackageParser {          boolean extractNativeLibs = true;          boolean isolatedSplits = false;          boolean isFeatureSplit = false; +        boolean isSplitRequired = false;          String configForSplit = null;          String usesSplitName = null; @@ -1717,6 +1721,8 @@ public class PackageParser {                  configForSplit = attrs.getAttributeValue(i);              } else if (attr.equals("isFeatureSplit")) {                  isFeatureSplit = attrs.getAttributeBooleanValue(i, false); +            } else if (attr.equals("isSplitRequired")) { +                isSplitRequired = attrs.getAttributeBooleanValue(i, false);              }          } @@ -1772,8 +1778,8 @@ public class PackageParser {          }          return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, -                configForSplit, usesSplitName, versionCode, versionCodeMajor, revisionCode, -                installLocation, verifiers, signingDetails, coreApp, debuggable, +                configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor, +                revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,                  multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);      } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 121b43275257..799f8e55cd18 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -46,6 +46,7 @@ import android.annotation.Nullable;  import android.annotation.TestApi;  import android.annotation.UnsupportedAppUsage;  import android.app.WindowConfiguration; +import android.content.LocaleProto;  import android.content.pm.ActivityInfo;  import android.content.pm.ActivityInfo.Config;  import android.os.Build; @@ -54,7 +55,9 @@ import android.os.Parcel;  import android.os.Parcelable;  import android.text.TextUtils;  import android.util.DisplayMetrics; +import android.util.proto.ProtoInputStream;  import android.util.proto.ProtoOutputStream; +import android.util.proto.WireTypeMismatchException;  import android.view.View;  import com.android.internal.util.XmlUtils; @@ -67,6 +70,7 @@ import java.io.IOException;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList; +import java.util.List;  import java.util.Locale;  /** @@ -1086,12 +1090,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration      /**       * Write to a protocol buffer output stream.       * Protocol buffer message definition at {@link android.content.ConfigurationProto} +     * Has the option to ignore fields that don't need to be persisted to disk.       *       * @param protoOutputStream Stream to write the Configuration object to.       * @param fieldId           Field Id of the Configuration as defined in the parent message +     * @param persisted         Note if this proto will be persisted to disk       * @hide       */ -    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) { +    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted) {          final long token = protoOutputStream.start(fieldId);          protoOutputStream.write(FONT_SCALE, fontScale);          protoOutputStream.write(MCC, mcc); @@ -1113,13 +1119,137 @@ public final class Configuration implements Parcelable, Comparable<Configuration          protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp);          protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp);          protoOutputStream.write(DENSITY_DPI, densityDpi); -        if (windowConfiguration != null) { +        // For persistence, we do not care about window configuration +        if (!persisted && windowConfiguration != null) {              windowConfiguration.writeToProto(protoOutputStream, WINDOW_CONFIGURATION);          }          protoOutputStream.end(token);      }      /** +     * Write to a protocol buffer output stream. +     * Protocol buffer message definition at {@link android.content.ConfigurationProto} +     * +     * @param protoOutputStream Stream to write the Configuration object to. +     * @param fieldId           Field Id of the Configuration as defined in the parent message +     * @hide +     */ +    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) { +        writeToProto(protoOutputStream, fieldId, false); +    } + +    /** +     * Read from a protocol buffer output stream. +     * Protocol buffer message definition at {@link android.content.ConfigurationProto} +     * +     * @param protoInputStream Stream to read the Configuration object from. +     * @param fieldId          Field Id of the Configuration as defined in the parent message +     * @hide +     */ +    public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throws IOException { +        final long token = protoInputStream.start(fieldId); +        final List<Locale> list = new ArrayList(); +        try { +            while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +                switch (protoInputStream.getFieldNumber()) { +                    case (int) FONT_SCALE: +                        fontScale = protoInputStream.readFloat(FONT_SCALE); +                        break; +                    case (int) MCC: +                        mcc = protoInputStream.readInt(MCC); +                        break; +                    case (int) MNC: +                        mnc = protoInputStream.readInt(MNC); +                        break; +                    case (int) LOCALES: +                        // Parse the Locale here to handle all the repeated Locales +                        // The LocaleList will be created when the message is completed +                        final long localeToken = protoInputStream.start(LOCALES); +                        String language = ""; +                        String country = ""; +                        String variant = ""; +                        try { +                            while (protoInputStream.nextField() +                                    != ProtoInputStream.NO_MORE_FIELDS) { +                                switch (protoInputStream.getFieldNumber()) { +                                    case (int) LocaleProto.LANGUAGE: +                                        language = protoInputStream.readString( +                                                LocaleProto.LANGUAGE); +                                        break; +                                    case (int) LocaleProto.COUNTRY: +                                        country = protoInputStream.readString(LocaleProto.COUNTRY); +                                        break; +                                    case (int) LocaleProto.VARIANT: +                                        variant = protoInputStream.readString(LocaleProto.VARIANT); +                                        break; +                                } +                            } +                        } catch (WireTypeMismatchException wtme) { +                            // rethrow for caller deal with +                            throw wtme; +                        } finally { +                            protoInputStream.end(localeToken); +                            list.add(new Locale(language, country, variant)); +                        } +                        break; +                    case (int) SCREEN_LAYOUT: +                        screenLayout = protoInputStream.readInt(SCREEN_LAYOUT); +                        break; +                    case (int) COLOR_MODE: +                        colorMode = protoInputStream.readInt(COLOR_MODE); +                        break; +                    case (int) TOUCHSCREEN: +                        touchscreen = protoInputStream.readInt(TOUCHSCREEN); +                        break; +                    case (int) KEYBOARD: +                        keyboard = protoInputStream.readInt(KEYBOARD); +                        break; +                    case (int) KEYBOARD_HIDDEN: +                        keyboardHidden = protoInputStream.readInt(KEYBOARD_HIDDEN); +                        break; +                    case (int) HARD_KEYBOARD_HIDDEN: +                        hardKeyboardHidden = protoInputStream.readInt(HARD_KEYBOARD_HIDDEN); +                        break; +                    case (int) NAVIGATION: +                        navigation = protoInputStream.readInt(NAVIGATION); +                        break; +                    case (int) NAVIGATION_HIDDEN: +                        navigationHidden = protoInputStream.readInt(NAVIGATION_HIDDEN); +                        break; +                    case (int) ORIENTATION: +                        orientation = protoInputStream.readInt(ORIENTATION); +                        break; +                    case (int) UI_MODE: +                        uiMode = protoInputStream.readInt(UI_MODE); +                        break; +                    case (int) SCREEN_WIDTH_DP: +                        screenWidthDp = protoInputStream.readInt(SCREEN_WIDTH_DP); +                        break; +                    case (int) SCREEN_HEIGHT_DP: +                        screenHeightDp = protoInputStream.readInt(SCREEN_HEIGHT_DP); +                        break; +                    case (int) SMALLEST_SCREEN_WIDTH_DP: +                        smallestScreenWidthDp = protoInputStream.readInt(SMALLEST_SCREEN_WIDTH_DP); +                        break; +                    case (int) DENSITY_DPI: +                        densityDpi = protoInputStream.readInt(DENSITY_DPI); +                        break; +                    case (int) WINDOW_CONFIGURATION: +                        windowConfiguration.readFromProto(protoInputStream, WINDOW_CONFIGURATION); +                        break; +                } +            } +        } finally { +            // Let caller handle any exceptions +            if (list.size() > 0) { +                //Create the LocaleList from the collected Locales +                setLocales(new LocaleList(list.toArray(new Locale[list.size()]))); +            } +            protoInputStream.end(token); +        } +    } + +    /**       * Write full {@link android.content.ResourcesConfigurationProto} to protocol buffer output       * stream.       * diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 01557c59f8ac..eb5c720d6309 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -649,7 +649,7 @@ public final class SQLiteDatabase extends SQLiteClosable {       * successful so far. Do not call setTransactionSuccessful before calling this. When this       * returns a new transaction will have been created but not marked as successful.       * @return true if the transaction was yielded -     * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock +     * @deprecated if the db is locked more than once (because of nested transactions) then the lock       *   will not be yielded. Use yieldIfContendedSafely instead.       */      @Deprecated diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java index 94f2ac085965..0d7b695d7f1d 100644 --- a/core/java/android/hardware/GeomagneticField.java +++ b/core/java/android/hardware/GeomagneticField.java @@ -31,7 +31,7 @@ import java.util.GregorianCalendar;   * Android may use a newer version of the model.   */  public class GeomagneticField { -    // The magnetic field at a given point, in nonoteslas in geodetic +    // The magnetic field at a given point, in nanoteslas in geodetic      // coordinates.      private float mX;      private float mY; @@ -278,7 +278,7 @@ public class GeomagneticField {      }      /** -     * @return  Horizontal component of the field strength in nonoteslas. +     * @return  Horizontal component of the field strength in nanoteslas.       */      public float getHorizontalStrength() {          return (float) Math.hypot(mX, mY); diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 92a814ca24c5..83998cc1c66a 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -348,7 +348,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan           * @hide           */          public AuthenticationResult(CryptoObject crypto) { -            // For compatibility, this extends from common base class as FingerprintManager does.              // Identifier and userId is not used for BiometricPrompt.              super(crypto, null /* identifier */, 0 /* userId */);          } @@ -410,8 +409,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan      }      /** -     * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts -     * scanning for a fingerprint. It terminates when {@link +     * This call warms up the biometric hardware, displays a system-provided dialog, and starts +     * scanning for a biometric. It terminates when {@link       * AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link       * AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)}, or when the user       * dismisses the system-provided dialog, at which point the crypto object becomes invalid. This @@ -453,8 +452,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan      }      /** -     * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts -     * scanning for a fingerprint. It terminates when {@link +     * This call warms up the biometric hardware, displays a system-provided dialog, and starts +     * scanning for a biometric. It terminates when {@link       * AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link       * AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)} is called, or when       * the user dismisses the system-provided dialog.  This operation can be canceled by using the diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 66613ea50357..873a24a3b53b 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -244,17 +244,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan      }      /** -     * Requests a pre-enrollment auth token to tie enrollment to the confirmation of +     * Requests an auth token to tie sensitive operations to the confirmation of       * existing device credentials (e.g. pin/pattern/password).       *       * @hide       */      @RequiresPermission(MANAGE_BIOMETRIC) -    public long preEnroll() { +    public long generateChallenge() {          long result = 0;          if (mService != null) {              try { -                result = mService.preEnroll(mToken); +                result = mService.generateChallenge(mToken);              } catch (RemoteException e) {                  throw e.rethrowFromSystemServer();              } @@ -263,16 +263,46 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan      }      /** -     * Finishes enrollment and cancels the current auth token. +     * Invalidates the current auth token.       *       * @hide       */      @RequiresPermission(MANAGE_BIOMETRIC) -    public int postEnroll() { +    public int revokeChallenge() {          int result = 0;          if (mService != null) {              try { -                result = mService.postEnroll(mToken); +                result = mService.revokeChallenge(mToken); +            } catch (RemoteException e) { +                throw e.rethrowFromSystemServer(); +            } +        } +        return result; +    } + +    /** +     * @hide +     */ +    @RequiresPermission(MANAGE_BIOMETRIC) +    public void setRequireAttention(boolean requireAttention, byte[] token) { +        if (mService != null) { +            try { +                mService.setRequireAttention(requireAttention, token); +            } catch (RemoteException e) { +                throw e.rethrowFromSystemServer(); +            } +        } +    } + +    /** +     * @hide +     */ +    @RequiresPermission(MANAGE_BIOMETRIC) +    public boolean getRequireAttention(byte[] token) { +        boolean result = true; +        if (mService != null) { +            try { +                mService.getRequireAttention(token);              } catch (RemoteException e) {                  throw e.rethrowFromSystemServer();              } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 50d07449493e..6681bd714779 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -66,10 +66,10 @@ interface IFaceService {      boolean isHardwareDetected(long deviceId, String opPackageName);      // Get a pre-enrollment authentication token -    long preEnroll(IBinder token); +    long generateChallenge(IBinder token);      // Finish an enrollment sequence and invalidate the authentication token -    int postEnroll(IBinder token); +    int revokeChallenge(IBinder token);      // Determine if a user has at least one enrolled face      boolean hasEnrolledFaces(int userId, String opPackageName); @@ -94,4 +94,8 @@ interface IFaceService {      // Enumerate all faces      void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver); + +    int setRequireAttention(boolean requireAttention, in byte [] token); + +    boolean getRequireAttention(in byte [] token);  } diff --git a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java b/core/java/android/hardware/location/ContextHubBroadcastReceiver.java new file mode 100644 index 000000000000..e0cc8b7de634 --- /dev/null +++ b/core/java/android/hardware/location/ContextHubBroadcastReceiver.java @@ -0,0 +1,102 @@ +/* + * Copyright 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.hardware.location; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; + +/** + * A BroadcastReceiver that can be used with the Context Hub Service notifications. + * + * @hide + */ +public class ContextHubBroadcastReceiver extends BroadcastReceiver { +    // The context at which this receiver operates in +    private Context mContext; + +    // The handler to post callbacks to when receiving Context Hub Service intents +    private Handler mHandler; + +    // The callback to be invoked when receiving Context Hub Service intents +    private ContextHubClientCallback mCallback; + +    // The string to use as the broadcast action for this receiver +    private String mAction; + +    // True when this receiver is registered to receive Intents, false otherwise +    private boolean mRegistered = false; + +    public ContextHubBroadcastReceiver(Context context, Handler handler, +                                       ContextHubClientCallback callback, String tag) { +        mContext = context; +        mHandler = handler; +        mCallback = callback; +        mAction = tag; +    } + +    /** +     * Registers this receiver to receive Intents from the Context Hub Service. This method must +     * only be invoked when the receiver is not registered. +     * +     * @throws IllegalStateException if the receiver is already registered +     */ +    public void register() throws IllegalStateException { +        if (mRegistered) { +            throw new IllegalStateException( +                "Cannot register ContextHubBroadcastReceiver multiple times"); +        } +        IntentFilter intentFilter = new IntentFilter(); +        intentFilter.addAction(mAction); +        mContext.registerReceiver(this, intentFilter, null /* broadcastPermission */, mHandler); +        mRegistered = true; +    } + +    /** +     * Unregisters this receiver. This method must only be invoked if {@link #register()} is +     * previously invoked. +     * +     * @throws IllegalStateException if the receiver is not yet registered +     */ +    public void unregister() throws IllegalStateException { +        if (!mRegistered) { +            throw new IllegalStateException( +                "Cannot unregister ContextHubBroadcastReceiver when not registered"); +        } +        mContext.unregisterReceiver(this); +        mRegistered = false; +    } + +    /** +     * Creates a new PendingIntent associated with this receiver. +     * +     * @param flags the flags {@link PendingIntent.Flags} to use for the PendingIntent +     * +     * @return a PendingIntent to receive notifications for this receiver +     */ +    public PendingIntent getPendingIntent(@PendingIntent.Flags int flags) { +        return PendingIntent.getBroadcast( +            mContext, 0 /* requestCode */, new Intent(mAction), flags); +    } + +    @Override +    public void onReceive(Context context, Intent intent) { +        // TODO: Implement this +    } +} diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java index 2335203eb100..917644db4202 100644 --- a/core/java/android/hardware/location/ContextHubClient.java +++ b/core/java/android/hardware/location/ContextHubClient.java @@ -18,6 +18,7 @@ package android.hardware.location;  import android.annotation.NonNull;  import android.annotation.RequiresPermission;  import android.annotation.SystemApi; +import android.app.PendingIntent;  import android.os.RemoteException;  import com.android.internal.util.Preconditions; @@ -100,6 +101,57 @@ public class ContextHubClient implements Closeable {      }      /** +     * Registers to receive persistent intents for a given nanoapp. +     * +     * This method should be used if the caller wants to receive notifications even after the +     * process exits. The client must have an open connection with the Context Hub Service (i.e. it +     * cannot have been closed through the {@link #close()} method). If registered successfully, +     * intents will be delivered regarding events for the specified nanoapp from the attached +     * Context Hub. Any unicast messages for this client will also be delivered. The intent will +     * have an extra {@link #EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which will +     * contain the type of the event. See {@link ContextHubManager.Event} for description of each +     * event type. +     * +     * When the intent is received, this client can be recreated through +     * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, +     * ContextHubClientCallback, Exectutor)}. When recreated, the client can be treated as the +     * same endpoint entity from a nanoapp's perspective, and can be continued to be used to send +     * messages even if the original process has exited. +     * +     * Intents will be delivered until it is unregistered through +     * {@link #unregisterIntent(PendingIntent)}. Note that the registration of this client will +     * continued to be maintained at the Context Hub Service until +     * {@link #unregisterIntent(PendingIntent)} is called for registered intents. +     * +     * See {@link ContextHubBroadcastReceiver} for a helper class to generate the +     * {@link PendingIntent} through a {@link BroadcastReceiver}, and maps an {@link Intent} to a +     * {@link ContextHubClientCallback}. +     * +     * @param intent    The PendingIntent to register for this client +     * @param nanoAppId the unique ID of the nanoapp to receive events for +     * @return true on success, false otherwise +     * +     * @hide +     */ +    public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) { +        // TODO: Implement this +        return false; +    } + +    /** +     * Unregisters an intent previously registered via {@link #registerIntent(PendingIntent, long)}. +     * If this intent has not been registered for this client, this method returns false. +     * +     * @return true on success, false otherwise +     * +     * @hide +     */ +    public boolean unregisterIntent(@NonNull PendingIntent intent) { +        // TODO: Implement this +        return false; +    } + +    /**       * Sends a message to a nanoapp through the Context Hub Service.       *       * This function returns RESULT_SUCCESS if the message has reached the HAL, but diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 12d0531bbf2b..36f3586aec2a 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -16,12 +16,14 @@  package android.hardware.location;  import android.annotation.CallbackExecutor; +import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission;  import android.annotation.SuppressLint;  import android.annotation.SystemApi;  import android.annotation.SystemService; +import android.app.PendingIntent;  import android.content.Context;  import android.os.Handler;  import android.os.HandlerExecutor; @@ -33,6 +35,8 @@ import android.util.Log;  import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.util.List;  import java.util.concurrent.Executor; @@ -49,6 +53,111 @@ import java.util.concurrent.Executor;  public final class ContextHubManager {      private static final String TAG = "ContextHubManager"; +    /** +     * An extra of type {@link ContextHubInfo} describing the source of the event. +     * +     * @hide +     */ +    public static final String EXTRA_CONTEXT_HUB_INFO = +            "android.hardware.location.extra.CONTEXT_HUB_INFO"; + +    /** +     * An extra of type {@link ContextHubManager.Event} describing the event type. +     * +     * @hide +     */ +    public static final String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE"; + +    /** +     * An extra of type long describing the ID of the nanoapp an event is for. +     * +     * @hide +     */ +    public static final String EXTRA_NANOAPP_ID = "android.location.hardware.extra.NANOAPP_ID"; + +    /** +     * An extra of type int describing the nanoapp-specific abort code. +     * +     * @hide +     */ +    public static final String EXTRA_NANOAPP_ABORT_CODE = +            "android.location.hardware.extra.NANOAPP_ABORT_CODE"; + +    /** +     * An extra of type {@link NanoAppMessage} describing contents of a message from a nanoapp. +     * +     * @hide +     */ +    public static final String EXTRA_MESSAGE = "android.location.hardware.extra.MESSAGE"; + +    /** +     * Constants describing the type of events from a Context Hub. +     * {@hide} +     */ +    @Retention(RetentionPolicy.SOURCE) +    @IntDef(prefix = { "EVENT_" }, value = { +        EVENT_NANOAPP_LOADED, +        EVENT_NANOAPP_UNLOADED, +        EVENT_NANOAPP_ENABLED, +        EVENT_NANOAPP_DISABLED, +        EVENT_NANOAPP_ABORTED, +        EVENT_NANOAPP_MESSAGE, +        EVENT_HUB_RESET, +    }) +    public @interface Event { } + +    /** +     * An event describing that a nanoapp has been loaded. Contains the EXTRA_NANOAPP_ID extra. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_LOADED = 0; + +    /** +     * An event describing that a nanoapp has been unloaded. Contains the EXTRA_NANOAPP_ID extra. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_UNLOADED = 1; + +    /** +     * An event describing that a nanoapp has been enabled. Contains the EXTRA_NANOAPP_ID extra. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_ENABLED = 2; + +    /** +     * An event describing that a nanoapp has been disabled. Contains the EXTRA_NANOAPP_ID extra. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_DISABLED = 3; + +    /** +     * An event describing that a nanoapp has aborted. Contains the EXTRA_NANOAPP_ID and +     * EXTRA_NANOAPP_ABORT_CODE extras. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_ABORTED = 4; + +    /** +     * An event containing a message sent from a nanoapp. Contains the EXTRA_NANOAPP_ID and +     * EXTRA_NANOAPP_MESSAGE extras. +     * +     * @hide +     */ +    public static final int EVENT_NANOAPP_MESSAGE = 5; + +    /** +     * An event describing that the Context Hub has reset. +     * +     * @hide +     */ +    public static final int EVENT_HUB_RESET = 6; + +      private final Looper mMainLooper;      private final IContextHubService mService;      private Callback mCallback; @@ -682,6 +791,57 @@ public final class ContextHubManager {      }      /** +     * Creates a ContextHubClient based on an Intent received by the Context Hub Service. +     * +     * This method is intended to be used after receiving an Intent received as a result of +     * {@link ContextHubClient.registerIntent(PendingIntent, long)}, and must have been created +     * through {@link #createClient(ContextHubInfo, ContextHubClientCallback, Executor)} or +     * equivalent at an earlier time. +     * +     * @param intent   the intent that is associated with a client +     * @param hubInfo  the hub to attach this client to +     * @param callback the notification callback to register +     * @param executor the executor to invoke the callback +     * @return the registered client object +     * +     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or the intent +     *                                  was not associated with a client +     * @throws IllegalStateException    if there were too many registered clients at the service +     * @throws NullPointerException     if intent, hubInfo, callback, or executor is null +     * +     * @hide +     */ +    @NonNull public ContextHubClient createClient( +            @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo, +            @NonNull ContextHubClientCallback callback, +            @NonNull @CallbackExecutor Executor executor) { +        // TODO: Implement this +        throw new UnsupportedOperationException("Not implemented yet"); +    } + +    /** +     * Equivalent to {@link #createClient(Intent, ContextHubInfo, ContextHubClientCallback, +     * Executor)} with the executor using the main thread's Looper. +     * +     * @param intent   the intent that is associated with a client +     * @param hubInfo  the hub to attach this client to +     * @param callback the notification callback to register +     * @return the registered client object +     * +     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or the intent +     *                                  was not associated with a client +     * @throws IllegalStateException    if there were too many registered clients at the service +     * @throws NullPointerException     if intent, hubInfo, or callback is null +     * +     * @hide +     */ +    @NonNull public ContextHubClient createClient( +            @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo, +            @NonNull ContextHubClientCallback callback) { +        return createClient(intent, hubInfo, callback, new HandlerExecutor(Handler.getMain())); +    } + +    /**       * Unregister a callback for receive messages from the context hub.       *       * @see Callback diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index ae12f93285a8..f7f627ebedc2 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -2803,18 +2803,22 @@ public class InputMethodService extends AbstractInputMethodService {      }      /** -     * @return The recommended height of the input method window. -     * An IME author can get the last input method's height as the recommended height -     * by calling this in -     * {@link android.inputmethodservice.InputMethodService#onStartInputView(EditorInfo, boolean)}. -     * If you don't need to use a predefined fixed height, you can avoid the window-resizing of IME -     * switching by using this value as a visible inset height. It's efficient for the smooth -     * transition between different IMEs. However, note that this may return 0 (or possibly -     * unexpectedly low height). You should thus avoid relying on the return value of this method -     * all the time. Please make sure to use a reasonable height for the IME. +     * Aimed to return the previous input method's {@link Insets#contentTopInsets}, but its actual +     * semantics has never been well defined. +     * +     * <p>Note that the previous document clearly mentioned that this method could return {@code 0} +     * at any time for whatever reason.  Now this method is just always returning {@code 0}.</p> +     * +     * @return on Android {@link android.os.Build.VERSION_CODES#Q} and later devices this method +     *         always returns {@code 0} +     * @deprecated the actual behavior of this method has never been well defined.  You cannot use +     *             this method in a reliable and predictable way       */ +    @Deprecated      public int getInputMethodWindowRecommendedHeight() { -        return mImm.getInputMethodWindowVisibleHeight(); +        Log.w(TAG, "getInputMethodWindowRecommendedHeight() is deprecated and now always returns 0." +                + " Do not use this method."); +        return 0;      }      /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f2e907833612..8333b817add0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -26,7 +26,6 @@ import android.annotation.UnsupportedAppUsage;  import android.app.PendingIntent;  import android.content.Context;  import android.content.Intent; -import android.content.pm.PackageManager;  import android.os.Binder;  import android.os.Build.VERSION_CODES;  import android.os.Bundle; @@ -3801,8 +3800,9 @@ public class ConnectivityManager {      private void unsupportedStartingFrom(int version) {          if (Process.myUid() == Process.SYSTEM_UID) { -            // The getApplicationInfo() call we make below is not supported in system context, and -            // we want to allow the system to use these APIs anyway. +            // The getApplicationInfo() call we make below is not supported in system context. Let +            // the call through here, and rely on the fact that ConnectivityService will refuse to +            // allow the system to use these APIs anyway.              return;          } @@ -3819,11 +3819,6 @@ public class ConnectivityManager {      // functions by accessing ConnectivityService directly. However, it should be clear that doing      // so is unsupported and may break in the future. http://b/22728205      private void checkLegacyRoutingApiAccess() { -        if (mContext.checkCallingOrSelfPermission("com.android.permission.INJECT_OMADM_SETTINGS") -                == PackageManager.PERMISSION_GRANTED) { -            return; -        } -          unsupportedStartingFrom(VERSION_CODES.M);      } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 6bd2e76cdf35..8681893702b4 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -30,6 +30,8 @@ import com.android.internal.telephony.TelephonyProperties;  import dalvik.system.VMRuntime; +import java.util.ArrayList; +import java.util.List;  import java.util.Objects;  /** @@ -1083,7 +1085,67 @@ public class Build {          return true;      } +    /** Build information for a particular device partition. */ +    public static class Partition { +        /** The name identifying the system partition. */ +        public static final String PARTITION_NAME_SYSTEM = "system"; + +        private String mName; +        private String mFingerprint; +        private long mTimeMs; + +        public Partition() {} + +        private Partition(String name, String fingerprint, long timeMs) { +            mName = name; +            mFingerprint = fingerprint; +            mTimeMs = timeMs; +        } + +        /** The name of this partition, e.g. "system", or "vendor" */ +        public String getName() { +            return mName; +        } + +        /** The build fingerprint of this partition, see {@link Build#FINGERPRINT}. */ +        public String getFingerprint() { +            return mFingerprint; +        } + +        /** The time (ms since epoch), at which this partition was built, see {@link Build#TIME}. */ +        public long getTimeMillis() { +            return mTimeMs; +        } +    } + +    /** +     * Get build information about partitions that have a separate fingerprint defined. +     * +     * The list includes partitions that are suitable candidates for over-the-air updates. This is +     * not an exhaustive list of partitions on the device. +     */ +    public static List<Partition> getPartitions() { +        ArrayList<Partition> partitions = new ArrayList(); + +        String[] names = new String[] { +            "bootimage", "odm", "product", "product_services", Partition.PARTITION_NAME_SYSTEM, +            "vendor" +        }; +        for (String name : names) { +            String fingerprint = SystemProperties.get("ro." + name + ".build.fingerprint"); +            if (TextUtils.isEmpty(fingerprint)) { +                continue; +            } +            long time = getLong("ro." + name + ".build.date.utc") * 1000; +            partitions.add(new Partition(name, fingerprint, time)); +        } + +        return partitions; +    } +      // The following properties only make sense for internal engineering builds. + +    /** The time at which the build was produced, given in milliseconds since the UNIX epoch. */      public static final long TIME = getLong("ro.build.date.utc") * 1000;      public static final String USER = getString("ro.build.user");      public static final String HOST = getString("ro.build.host"); diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index f2e0bddb93aa..54be6393e651 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -44,6 +44,8 @@ public class GraphicsEnvironment {      private static final boolean DEBUG = false;      private static final String TAG = "GraphicsEnvironment";      private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; +    private static final String ANGLE_PACKAGE_NAME = "com.android.angle"; +    private static final String GLES_MODE_METADATA_KEY = "com.android.angle.GLES_MODE";      private ClassLoader mClassLoader;      private String mLayerPath; @@ -54,6 +56,7 @@ public class GraphicsEnvironment {       */      public void setup(Context context) {          setupGpuLayers(context); +        setupAngle(context);          chooseDriver(context);      } @@ -121,7 +124,6 @@ public class GraphicsEnvironment {                      }                  }              } -          }          // Include the app's lib directory in all cases @@ -131,6 +133,80 @@ public class GraphicsEnvironment {      }      /** +     * Pass ANGLE details down to trigger enable logic +     */ +    private static void setupAngle(Context context) { + +        String angleEnabledApp = +                Settings.Global.getString(context.getContentResolver(), +                                          Settings.Global.ANGLE_ENABLED_APP); + +        String packageName = context.getPackageName(); + +        boolean devOptIn = false; +        if ((angleEnabledApp != null && packageName != null) +                && (!angleEnabledApp.isEmpty() && !packageName.isEmpty()) +                && angleEnabledApp.equals(packageName)) { + +            if (DEBUG) Log.v(TAG, packageName + " opted in for ANGLE via Developer Setting"); + +            devOptIn = true; +        } + +        ApplicationInfo appInfo; +        try { +            appInfo = context.getPackageManager().getApplicationInfo(packageName, +                PackageManager.GET_META_DATA); +        } catch (PackageManager.NameNotFoundException e) { +            Log.w(TAG, "Failed to get info about current application: " + packageName); +            return; +        } + +        String appPref = "dontcare"; +        final BaseBundle metadata = appInfo.metaData; +        if (metadata != null) { +            final String glesMode = metadata.getString(GLES_MODE_METADATA_KEY); +            if (glesMode != null) { +                if (glesMode.equals("angle")) { +                    appPref = "angle"; +                    if (DEBUG) Log.v(TAG, packageName + " opted for ANGLE via AndroidManifest"); +                } else if (glesMode.equals("native")) { +                    appPref = "native"; +                    if (DEBUG) Log.v(TAG, packageName + " opted for NATIVE via AndroidManifest"); +                } else { +                    Log.w(TAG, "Unrecognized GLES_MODE (\"" + glesMode + "\") for " + packageName +                               + ". Supported values are \"angle\" or \"native\""); +                } +            } +        } + +        ApplicationInfo angleInfo; +        try { +            angleInfo = context.getPackageManager().getApplicationInfo(ANGLE_PACKAGE_NAME, +                PackageManager.MATCH_SYSTEM_ONLY); +        } catch (PackageManager.NameNotFoundException e) { +            Log.w(TAG, "ANGLE package '" + ANGLE_PACKAGE_NAME + "' not installed"); +            return; +        } + +        String abi = chooseAbi(angleInfo); + +        // Build a path that includes installed native libs and APK +        StringBuilder sb = new StringBuilder(); +        sb.append(angleInfo.nativeLibraryDir) +            .append(File.pathSeparator) +            .append(angleInfo.sourceDir) +            .append("!/lib/") +            .append(abi); +        String paths = sb.toString(); + +        if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); + +        // Further opt-in logic is handled in native, so pass relevant info down +        setAngleInfo(paths, packageName, appPref, devOptIn); +    } + +    /**       * Choose whether the current process should use the builtin or an updated driver.       */      private static void chooseDriver(Context context) { @@ -218,4 +294,6 @@ public class GraphicsEnvironment {      private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);      private static native void setDebugLayers(String layers);      private static native void setDriverPath(String path); +    private static native void setAngleInfo(String path, String appPackage, String appPref, +                                            boolean devOptIn);  } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 6fab3c412ae5..0f64c4531bc3 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -483,6 +483,8 @@ public class Process {       * @param appDataDir null-ok the data directory of the app.       * @param invokeWith null-ok the command to invoke with.       * @param packageName null-ok the name of the package this process belongs to. +     * @param packagesForUid null-ok all the packages with the same uid as this process. +     * @param visibleVols null-ok storage volumes that can be accessed by this process.       * @param zygoteArgs Additional arguments to supply to the zygote process.       *        * @return An object that describes the result of the attempt to start the process. @@ -501,10 +503,13 @@ public class Process {                                    @Nullable String appDataDir,                                    @Nullable String invokeWith,                                    @Nullable String packageName, +                                  @Nullable String[] packagesForUid, +                                  @Nullable String[] visibleVols,                                    @Nullable String[] zygoteArgs) {          return zygoteProcess.start(processClass, niceName, uid, gid, gids,                      runtimeFlags, mountExternal, targetSdkVersion, seInfo, -                    abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs); +                    abi, instructionSet, appDataDir, invokeWith, packageName, +                    packagesForUid, visibleVols, zygoteArgs);      }      /** @hide */ @@ -519,10 +524,13 @@ public class Process {                                    @Nullable String appDataDir,                                    @Nullable String invokeWith,                                    @Nullable String packageName, +                                  @Nullable String[] packagesForUid, +                                  @Nullable String[] visibleVols,                                    @Nullable String[] zygoteArgs) {          return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,                      runtimeFlags, mountExternal, targetSdkVersion, seInfo, -                    abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs); +                    abi, instructionSet, appDataDir, invokeWith, packageName, +                    packagesForUid, visibleVols, zygoteArgs);      }      /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b0891050634c..128217001b17 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -256,6 +256,7 @@ public class UserManager {      /**       * Specifies if a user is disallowed from enabling the       * "Unknown Sources" setting, that allows installation of apps from unknown sources. +     * Unknown sources exclude adb and special apps such as trusted app stores.       * The default value is <code>false</code>.       *       * <p>Key for user restrictions. @@ -267,6 +268,22 @@ public class UserManager {      public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";      /** +     * This restriction is a device-wide version of {@link DISALLOW_INSTALL_UNKNOWN_SOURCES}. +     * +     * Specifies if all users on the device are disallowed from enabling the +     * "Unknown Sources" setting, that allows installation of apps from unknown sources. +     * The default value is <code>false</code>. +     * +     * <p>Key for user restrictions. +     * <p>Type: Boolean +     * @see DevicePolicyManager#addUserRestriction(ComponentName, String) +     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) +     * @see #getUserRestrictions() +     */ +    public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = +            "no_install_unknown_sources_globally"; + +    /**       * Specifies if a user is disallowed from configuring bluetooth.       * This does <em>not</em> restrict the user from turning bluetooth on or off.       * The default value is <code>false</code>. @@ -1669,8 +1686,9 @@ public class UserManager {       /**       * @hide       * Returns whether the given user has been disallowed from performing certain actions -     * or setting certain settings through UserManager. This method disregards restrictions -     * set by device policy. +     * or setting certain settings through UserManager (e.g. this type of restriction would prevent +     * the guest user from doing certain things, such as making calls). This method disregards +     * restrictions set by device policy.       * @param restrictionKey the string key representing the restriction       * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.       */ diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 99181acb03c7..7fd0a4b66d66 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -215,6 +215,8 @@ public class ZygoteProcess {       * @param appDataDir null-ok the data directory of the app.       * @param invokeWith null-ok the command to invoke with.       * @param packageName null-ok the name of the package this process belongs to. +     * @param packagesForUid null-ok all the packages with the same uid as this process. +     * @param visibleVols null-ok storage volumes that can be accessed by this process.       * @param zygoteArgs Additional arguments to supply to the zygote process.       *       * @return An object that describes the result of the attempt to start the process. @@ -231,12 +233,14 @@ public class ZygoteProcess {                                                    @Nullable String appDataDir,                                                    @Nullable String invokeWith,                                                    @Nullable String packageName, +                                                  @Nullable String[] packagesForUid, +                                                  @Nullable String[] visibleVols,                                                    @Nullable String[] zygoteArgs) {          try {              return startViaZygote(processClass, niceName, uid, gid, gids,                      runtimeFlags, mountExternal, targetSdkVersion, seInfo,                      abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, -                    packageName, zygoteArgs); +                    packageName, packagesForUid, visibleVols, zygoteArgs);          } catch (ZygoteStartFailedEx ex) {              Log.e(LOG_TAG,                      "Starting VM process through Zygote failed"); @@ -355,6 +359,8 @@ public class ZygoteProcess {       * @param startChildZygote Start a sub-zygote. This creates a new zygote process       * that has its state cloned from this zygote process.       * @param packageName null-ok the name of the package this process belongs to. +     * @param packagesForUid null-ok all the packages with the same uid as this process. +     * @param visibleVols null-ok storage volumes that can be accessed by this process.       * @param extraArgs Additional arguments to supply to the zygote process.       * @return An object that describes the result of the attempt to start the process.       * @throws ZygoteStartFailedEx if process start failed for any reason @@ -372,6 +378,8 @@ public class ZygoteProcess {                                                        @Nullable String invokeWith,                                                        boolean startChildZygote,                                                        @Nullable String packageName, +                                                      @Nullable String[] packagesForUid, +                                                      @Nullable String[] visibleVols,                                                        @Nullable String[] extraArgs)                                                        throws ZygoteStartFailedEx {          ArrayList<String> argsForZygote = new ArrayList<String>(); @@ -439,6 +447,32 @@ public class ZygoteProcess {              argsForZygote.add("--package-name=" + packageName);          } +        if (packagesForUid != null && packagesForUid.length > 0) { +            final StringBuilder sb = new StringBuilder(); +            sb.append("--packages-for-uid="); + +            for (int i = 0; i < packagesForUid.length; ++i) { +                if (i != 0) { +                    sb.append(','); +                } +                sb.append(packagesForUid[i]); +            } +            argsForZygote.add(sb.toString()); +        } + +        if (visibleVols != null && visibleVols.length > 0) { +            final StringBuilder sb = new StringBuilder(); +            sb.append("--visible-vols="); + +            for (int i = 0; i < visibleVols.length; ++i) { +                if (i != 0) { +                    sb.append(','); +                } +                sb.append(visibleVols[i]); +            } +            argsForZygote.add(sb.toString()); +        } +          argsForZygote.add(processClass);          if (extraArgs != null) { @@ -746,7 +780,8 @@ public class ZygoteProcess {              result = startViaZygote(processClass, niceName, uid, gid,                      gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,                      abi, instructionSet, null /* appDataDir */, null /* invokeWith */, -                    true /* startChildZygote */, null /* packageName */, extraArgs); +                    true /* startChildZygote */, null /* packageName */, +                    null /* packagesForUid */, null /* visibleVolumes */, extraArgs);          } catch (ZygoteStartFailedEx ex) {              throw new RuntimeException("Starting child-zygote through Zygote failed", ex);          } diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index d850e27e913f..1f54ea53facc 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -89,8 +89,13 @@ public abstract class StorageManagerInternal {       * @param appId The appId for the given package.       * @param sharedUserId The sharedUserId for given package if it specified       *      {@code android:sharedUserId} in the manifest, otherwise {@code null} -     * @param userId +     * @param userId The userId in which the storage needs to be mounted.       */      public abstract void mountExternalStorageForApp(String packageName, int appId,              String sharedUserId, int userId); + +    /** +     * @return Labels of storage volumes that are visible to the given userId. +     */ +    public abstract String[] getVisibleVolumesForUser(int userId);  } diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index afd383691300..e55afb69bab9 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -157,7 +157,7 @@ public class VolumeInfo implements Parcelable {      public final DiskInfo disk;      public final String partGuid;      public int mountFlags = 0; -    public int mountUserId = -1; +    public int mountUserId = UserHandle.USER_NULL;      @UnsupportedAppUsage      public int state = STATE_UNMOUNTED;      public String fsType; diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index ee64ca2b8673..8c40e0e6cb8c 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -942,13 +942,26 @@ public final class DocumentsContract {          return false;      } -    /** {@hide} */ +    /** +     * Test if the given URI represents roots backed by {@link DocumentsProvider}. +     * +     * @see #buildRootsUri(String) +     * +     * {@hide} +     */ +    public static boolean isRootsUri(Context context, @Nullable Uri uri) { +        return isRootUri(context, uri, 1 /* pathSize */); +    } + +    /** +     * Test if the given URI represents specific root backed by {@link DocumentsProvider}. +     * +     * @see #buildRootUri(String, String) +     * +     * {@hide} +     */      public static boolean isRootUri(Context context, @Nullable Uri uri) { -        if (isContentUri(uri) && isDocumentsProvider(context, uri.getAuthority())) { -            final List<String> paths = uri.getPathSegments(); -            return (paths.size() == 2 && PATH_ROOT.equals(paths.get(0))); -        } -        return false; +        return isRootUri(context, uri, 2 /* pathSize */);      }      /** {@hide} */ @@ -967,6 +980,14 @@ public final class DocumentsContract {          return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));      } +    private static boolean isRootUri(Context context, @Nullable Uri uri, int pathSize) { +        if (isContentUri(uri) && isDocumentsProvider(context, uri.getAuthority())) { +            final List<String> paths = uri.getPathSegments(); +            return (paths.size() == pathSize && PATH_ROOT.equals(paths.get(0))); +        } +        return false; +    } +      private static boolean isDocumentsProvider(Context context, String authority) {          final Intent intent = new Intent(PROVIDER_INTERFACE);          final List<ResolveInfo> infos = context.getPackageManager() diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 82459b13a4eb..828fd7386d80 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -1318,18 +1318,6 @@ public final class MediaStore {          }          public static final class Media implements AudioColumns { - -            private static final String[] EXTERNAL_PATHS; - -            static { -                String secondary_storage = System.getenv("SECONDARY_STORAGE"); -                if (secondary_storage != null) { -                    EXTERNAL_PATHS = secondary_storage.split(":"); -                } else { -                    EXTERNAL_PATHS = new String[0]; -                } -            } -              /**               * Get the content:// style URI for the audio media table on the               * given volume. @@ -1343,14 +1331,9 @@ public final class MediaStore {              }              public static Uri getContentUriForPath(String path) { -                for (String ep : EXTERNAL_PATHS) { -                    if (path.startsWith(ep)) { -                        return EXTERNAL_CONTENT_URI; -                    } -                } - -                return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ? -                        EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI); +                return (path.startsWith( +                        Environment.getStorageDirectory().getAbsolutePath() + "/") +                        ? EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);              }              /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index aa178fb9ff36..e1c0fe52de37 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7267,12 +7267,12 @@ public final class Settings {          private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;          /** -         * Whether the device should pulse on reach gesture. +         * Gesture that wakes up the lock screen.           * @hide           */ -        public static final String DOZE_REACH_GESTURE = "doze_reach_gesture"; +        public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_lock_screen_gesture"; -        private static final Validator DOZE_REACH_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; +        private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;          /**           * Gesture that wakes up the display, showing the ambient version of the status bar. @@ -7689,6 +7689,15 @@ public final class Settings {                  BOOLEAN_VALIDATOR;          /** +         * Whether or not face unlock is allowed for apps (through BiometricPrompt). +         * @hide +         */ +        public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled"; + +        private static final Validator FACE_UNLOCK_APP_ENABLED_VALIDATOR = +                BOOLEAN_VALIDATOR; + +        /**           * Whether the assist gesture should be enabled.           *           * @hide @@ -8184,11 +8193,12 @@ public final class Settings {              DOZE_ALWAYS_ON,              DOZE_PICK_UP_GESTURE,              DOZE_DOUBLE_TAP_GESTURE, -            DOZE_REACH_GESTURE, +            DOZE_WAKE_LOCK_SCREEN_GESTURE,              DOZE_WAKE_SCREEN_GESTURE,              NFC_PAYMENT_DEFAULT_COMPONENT,              AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,              FACE_UNLOCK_KEYGUARD_ENABLED, +            FACE_UNLOCK_APP_ENABLED,              ASSIST_GESTURE_ENABLED,              ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,              ASSIST_GESTURE_WAKE_ENABLED, @@ -8331,12 +8341,13 @@ public final class Settings {              VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);              VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);              VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR); -            VALIDATORS.put(DOZE_REACH_GESTURE, DOZE_REACH_GESTURE_VALIDATOR); +            VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);              VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);              VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);              VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,                      AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);              VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR); +            VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);              VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);              VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,                      ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR); @@ -9593,8 +9604,7 @@ public final class Settings {           * Use the old dnsmasq DHCP server for tethering instead of the framework implementation.           *           * Integer values are interpreted as boolean, and the absence of an explicit setting -         * is interpreted as |true|. -         * TODO: make the default |false| +         * is interpreted as |false|.           * @hide           */          public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = @@ -10811,6 +10821,12 @@ public final class Settings {                  = "activity_starts_logging_enabled";          /** +         * @hide +         * @see com.android.server.appbinding.AppBindingConstants +         */ +        public static final String APP_BINDING_CONSTANTS = "app_binding_constants"; + +        /**           * App ops specific settings.           * This is encoded as a key=value list, separated by commas. Ex:           * @@ -11570,6 +11586,12 @@ public final class Settings {          public static final String GPU_DEBUG_APP = "gpu_debug_app";          /** +         * App should try to use ANGLE +         * @hide +         */ +        public static final String ANGLE_ENABLED_APP = "angle_enabled_app"; + +        /**           * Ordered GPU debug layer list           * i.e. <layer1>:<layer2>:...:<layerN>           * @hide diff --git a/core/java/android/text/NativeLineBreaker.java b/core/java/android/text/NativeLineBreaker.java index 2bcfa5fe0857..94e10e89acbd 100644 --- a/core/java/android/text/NativeLineBreaker.java +++ b/core/java/android/text/NativeLineBreaker.java @@ -21,6 +21,7 @@ import android.annotation.IntDef;  import android.annotation.IntRange;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.annotation.Px;  import dalvik.annotation.optimization.CriticalNative;  import dalvik.annotation.optimization.FastNative; @@ -258,16 +259,91 @@ public class NativeLineBreaker {      /**       * A result object of a line breaking       */ -    public static class LineBreaks { -        public int breakCount; -        private static final int INITIAL_SIZE = 16; -        public int[] breaks = new int[INITIAL_SIZE]; -        public float[] widths = new float[INITIAL_SIZE]; -        public float[] ascents = new float[INITIAL_SIZE]; -        public float[] descents = new float[INITIAL_SIZE]; -        // TODO: Introduce Hyphenator for explaining the meaning of flags. -        public int[] flags = new int[INITIAL_SIZE]; -        // breaks, widths, and flags should all have the same length +    public static class Result { +        // Following two contstant must be synced with minikin's line breaker. +        private static final int TAB_MASK = 0x20000000; +        private static final int HYPHEN_MASK = 0xFF; + +        private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( +                Result.class.getClassLoader(), nGetReleaseResultFunc(), 32); +        private final long mPtr; + +        private Result(long ptr) { +            mPtr = ptr; +            sRegistry.registerNativeAllocation(this, mPtr); +        } + +        /** +         * Returns a number of line count. +         * +         * @return number of lines +         */ +        public @IntRange(from = 0) int getLineCount() { +            return nGetLineCount(mPtr); +        } + +        /** +         * Returns a break offset of the line. +         * +         * @param lineIndex an index of the line. +         * @return the break offset. +         */ +        public @IntRange(from = 0) int getLineBreakOffset(@IntRange(from = 0) int lineIndex) { +            return nGetLineBreakOffset(mPtr, lineIndex); +        } + +        /** +         * Returns a width of the line in pixels. +         * +         * @param lineIndex an index of the line. +         * @return a width of the line in pixexls +         */ +        public @Px float getLineWidth(@IntRange(from = 0) int lineIndex) { +            return nGetLineWidth(mPtr, lineIndex); +        } + +        /** +         * Returns an entier font ascent of the line in pixels. +         * +         * @param lineIndex an index of the line. +         * @return an entier font ascent of the line in pixels. +         */ +        public @Px float getLineAscent(@IntRange(from = 0) int lineIndex) { +            return nGetLineAscent(mPtr, lineIndex); +        } + +        /** +         * Returns an entier font descent of the line in pixels. +         * +         * @param lineIndex an index of the line. +         * @return an entier font descent of the line in pixels. +         */ +        public @Px float getLineDescent(@IntRange(from = 0) int lineIndex) { +            return nGetLineDescent(mPtr, lineIndex); +        } + +        /** +         * Returns true if the line has a TAB character. +         * +         * @param lineIndex an index of the line. +         * @return true if the line has a TAB character +         */ +        public boolean hasLineTab(int lineIndex) { +            return (nGetLineFlag(mPtr, lineIndex) & TAB_MASK) != 0; +        } + +        /** +         * Returns a packed packed hyphen edit for the line. +         * +         * @param lineIndex an index of the line. +         * @return a packed hyphen edit for the line. +         * @see android.text.Hyphenator#unpackStartHyphenEdit(int) +         * @see android.text.Hyphenator#unpackEndHyphenEdit(int) +         * @see android.text.Hyphenator#packHyphenEdit(int,int) +         */ +        public int getLineHyphenEdit(int lineIndex) { +            return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK); +        }      }      private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( @@ -294,14 +370,12 @@ public class NativeLineBreaker {       * @param measuredPara a result of the text measurement       * @param constraints for a single paragraph       * @param lineNumber a line number of this paragraph -     * @param out object to set line break information for the given paragraph       */ -    public void computeLineBreaks( +    public Result computeLineBreaks(              @NonNull NativeMeasuredParagraph measuredPara,              @NonNull ParagraphConstraints constraints, -            @IntRange(from = 0) int lineNumber, -            @NonNull LineBreaks out) { -        out.breakCount = nComputeLineBreaks( +            @IntRange(from = 0) int lineNumber) { +        return new Result(nComputeLineBreaks(                  mNativePtr,                  // Inputs @@ -313,17 +387,7 @@ public class NativeLineBreaker {                  constraints.mWidth,                  constraints.mVariableTabStops,                  constraints.mDefaultTabStop, -                lineNumber, - -                // Outputs -                out, -                out.breaks.length, -                out.breaks, -                out.widths, -                out.ascents, -                out.descents, -                out.flags); - +                lineNumber));      }      @FastNative @@ -341,7 +405,7 @@ public class NativeLineBreaker {      // arrays do not have to be resized      // The individual character widths will be returned in charWidths. The length of      // charWidths must be at least the length of the text. -    private static native int nComputeLineBreaks( +    private static native long nComputeLineBreaks(              /* non zero */ long nativePtr,              // Inputs @@ -353,14 +417,21 @@ public class NativeLineBreaker {              @FloatRange(from = 0.0f) float restWidth,              @Nullable int[] variableTabStops,              int defaultTabStop, -            @IntRange(from = 0) int indentsOffset, - -            // Outputs -            @NonNull LineBreaks recycle, -            @IntRange(from  = 0) int recycleLength, -            @NonNull int[] recycleBreaks, -            @NonNull float[] recycleWidths, -            @NonNull float[] recycleAscents, -            @NonNull float[] recycleDescents, -            @NonNull int[] recycleFlags); +            @IntRange(from = 0) int indentsOffset); + +    // Result accessors +    @CriticalNative +    private static native int nGetLineCount(long ptr); +    @CriticalNative +    private static native int nGetLineBreakOffset(long ptr, int idx); +    @CriticalNative +    private static native float nGetLineWidth(long ptr, int idx); +    @CriticalNative +    private static native float nGetLineAscent(long ptr, int idx); +    @CriticalNative +    private static native float nGetLineDescent(long ptr, int idx); +    @CriticalNative +    private static native int nGetLineFlag(long ptr, int idx); +    @CriticalNative +    private static native long nGetReleaseResultFunc();  } diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index c5fabaf2d840..0d29da00f7c9 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -1610,13 +1610,14 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable      public boolean equals(Object o) {          if (o instanceof Spanned &&                  toString().equals(o.toString())) { -            Spanned other = (Spanned) o; +            final Spanned other = (Spanned) o;              // Check span data -            Object[] otherSpans = other.getSpans(0, other.length(), Object.class); +            final Object[] otherSpans = other.getSpans(0, other.length(), Object.class); +            final Object[] thisSpans = getSpans(0, length(), Object.class);              if (mSpanCount == otherSpans.length) {                  for (int i = 0; i < mSpanCount; ++i) { -                    Object thisSpan = mSpans[i]; -                    Object otherSpan = otherSpans[i]; +                    final Object thisSpan = thisSpans[i]; +                    final Object otherSpan = otherSpans[i];                      if (thisSpan == this) {                          if (other != otherSpan ||                                  getSpanStart(thisSpan) != other.getSpanStart(otherSpan) || diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index 7acd5399792c..a9866335f271 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -16,12 +16,13 @@  package android.text; +import android.annotation.UnsupportedAppUsage; +  import com.android.internal.util.ArrayUtils;  import com.android.internal.util.GrowingArrayUtils;  import libcore.util.EmptyArray; -import android.annotation.UnsupportedAppUsage;  import java.lang.reflect.Array;  /* package */ abstract class SpannableStringInternal @@ -502,13 +503,14 @@ import java.lang.reflect.Array;      public boolean equals(Object o) {          if (o instanceof Spanned &&                  toString().equals(o.toString())) { -            Spanned other = (Spanned) o; +            final Spanned other = (Spanned) o;              // Check span data -            Object[] otherSpans = other.getSpans(0, other.length(), Object.class); +            final Object[] otherSpans = other.getSpans(0, other.length(), Object.class); +            final Object[] thisSpans = getSpans(0, length(), Object.class);              if (mSpanCount == otherSpans.length) {                  for (int i = 0; i < mSpanCount; ++i) { -                    Object thisSpan = mSpans[i]; -                    Object otherSpan = otherSpans[i]; +                    final Object thisSpan = thisSpans[i]; +                    final Object otherSpan = otherSpans[i];                      if (thisSpan == this) {                          if (other != otherSpan ||                                  getSpanStart(thisSpan) != other.getSpanStart(otherSpan) || diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index e1ffef01feae..d2f085369448 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -599,7 +599,14 @@ public class StaticLayout extends Layout {          float ellipsizedWidth = b.mEllipsizedWidth;          TextUtils.TruncateAt ellipsize = b.mEllipsize;          final boolean addLastLineSpacing = b.mAddLastLineLineSpacing; -        NativeLineBreaker.LineBreaks lineBreaks = new NativeLineBreaker.LineBreaks(); + +        int lineBreakCapacity = 0; +        int[] breaks = null; +        float[] lineWidths = null; +        float[] ascents = null; +        float[] descents = null; +        boolean[] hasTabs = null; +        int[] hyphenEdits = null;          mLineCount = 0;          mEllipsized = false; @@ -732,14 +739,27 @@ public class StaticLayout extends Layout {              constraints.setIndent(firstWidth, firstWidthLineCount);              constraints.setTabStops(variableTabStops, TAB_INCREMENT); -            lineBreaker.computeLineBreaks(measuredPara.getNativeMeasuredParagraph(), -                    constraints, mLineCount, lineBreaks); -            int breakCount = lineBreaks.breakCount; -            final int[] breaks = lineBreaks.breaks; -            final float[] lineWidths = lineBreaks.widths; -            final float[] ascents = lineBreaks.ascents; -            final float[] descents = lineBreaks.descents; -            final int[] flags = lineBreaks.flags; +            NativeLineBreaker.Result res = lineBreaker.computeLineBreaks( +                    measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount); +            int breakCount = res.getLineCount(); +            if (lineBreakCapacity < breakCount) { +                lineBreakCapacity = breakCount; +                breaks = new int[lineBreakCapacity]; +                lineWidths = new float[lineBreakCapacity]; +                ascents = new float[lineBreakCapacity]; +                descents = new float[lineBreakCapacity]; +                hasTabs = new boolean[lineBreakCapacity]; +                hyphenEdits = new int[lineBreakCapacity]; +            } + +            for (int i = 0; i < breakCount; ++i) { +                breaks[i] = res.getLineBreakOffset(i); +                lineWidths[i] = res.getLineWidth(i); +                ascents[i] = res.getLineAscent(i); +                descents[i] = res.getLineDescent(i); +                hasTabs[i] = res.hasLineTab(i); +                hyphenEdits[i] = res.getLineHyphenEdit(i); +            }              final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;              final boolean ellipsisMayBeApplied = ellipsize != null @@ -750,7 +770,7 @@ public class StaticLayout extends Layout {                      && ellipsisMayBeApplied) {                  // Calculate width                  float width = 0; -                int flag = 0;  // XXX May need to also have starting hyphen edit +                boolean hasTab = false;  // XXX May need to also have starting hyphen edit                  for (int i = remainingLineCount - 1; i < breakCount; i++) {                      if (i == breakCount - 1) {                          width += lineWidths[i]; @@ -759,12 +779,12 @@ public class StaticLayout extends Layout {                              width += measuredPara.getCharWidthAt(j - paraStart);                          }                      } -                    flag |= flags[i] & TAB_MASK; +                    hasTab |= hasTabs[i];                  }                  // Treat the last line and overflowed lines as a single line.                  breaks[remainingLineCount - 1] = breaks[breakCount - 1];                  lineWidths[remainingLineCount - 1] = width; -                flags[remainingLineCount - 1] = flag; +                hasTabs[remainingLineCount - 1] = hasTab;                  breakCount = remainingLineCount;              } @@ -821,8 +841,8 @@ public class StaticLayout extends Layout {                      v = out(source, here, endPos,                              ascent, descent, fmTop, fmBottom,                              v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, -                            flags[breakIndex], needMultiply, measuredPara, bufEnd, -                            includepad, trackpad, addLastLineSpacing, chs, +                            hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply, +                            measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,                              paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],                              paint, moreChars); @@ -860,7 +880,7 @@ public class StaticLayout extends Layout {                      fm.top, fm.bottom,                      v,                      spacingmult, spacingadd, null, -                    null, fm, 0, +                    null, fm, false, 0,                      needMultiply, measuredPara, bufEnd,                      includepad, trackpad, addLastLineSpacing, null,                      bufStart, ellipsize, @@ -871,7 +891,8 @@ public class StaticLayout extends Layout {      private int out(final CharSequence text, final int start, final int end, int above, int below,              int top, int bottom, int v, final float spacingmult, final float spacingadd,              final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm, -            final int flags, final boolean needMultiply, @NonNull final MeasuredParagraph measured, +            final boolean hasTab, final int hyphenEdit, final boolean needMultiply, +            @NonNull final MeasuredParagraph measured,              final int bufEnd, final boolean includePad, final boolean trackPad,              final boolean addLastLineLineSpacing, final char[] chs,              final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth, @@ -1005,8 +1026,8 @@ public class StaticLayout extends Layout {          // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining          // one bit for start field -        lines[off + TAB] |= flags & TAB_MASK; -        lines[off + HYPHEN] = flags; +        lines[off + TAB] |= hasTab ? TAB_MASK : 0; +        lines[off + HYPHEN] = hyphenEdit;          lines[off + DIR] |= dir << DIR_SHIFT;          mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart); diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index c17cfd500827..2dc4f6001a06 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -16,11 +16,13 @@  package android.text.style; +import android.annotation.Nullable;  import android.content.Context;  import android.content.res.ColorStateList;  import android.content.res.TypedArray;  import android.graphics.LeakyTypefaceStorage;  import android.graphics.Typeface; +import android.graphics.fonts.Font;  import android.os.Parcel;  import android.text.ParcelableSpan;  import android.text.TextPaint; @@ -38,6 +40,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl      private final ColorStateList mTextColorLink;      private final Typeface mTypeface; +    private final int mTextFontWeight; + +    private final float mShadowRadius; +    private final float mShadowDx; +    private final float mShadowDy; +    private final int mShadowColor; + +    private final boolean mHasElegantTextHeight; +    private final boolean mElegantTextHeight; +    private final boolean mHasLetterSpacing; +    private final float mLetterSpacing; + +    private final String mFontFeatureSettings; +    private final String mFontVariationSettings; +      /**       * Uses the specified TextAppearance resource to determine the       * text appearance.  The <code>appearance</code> should be, for example, @@ -104,6 +121,34 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl              }          } +        mTextFontWeight = a.getInt(com.android.internal.R.styleable +                .TextAppearance_textFontWeight, -1); + +        mShadowRadius = a.getFloat(com.android.internal.R.styleable +                .TextAppearance_shadowRadius, 0.0f); +        mShadowDx = a.getFloat(com.android.internal.R.styleable +                .TextAppearance_shadowDx, 0.0f); +        mShadowDy = a.getFloat(com.android.internal.R.styleable +                .TextAppearance_shadowDy, 0.0f); +        mShadowColor = a.getInt(com.android.internal.R.styleable +                .TextAppearance_shadowColor, 0); + +        mHasElegantTextHeight = a.hasValue(com.android.internal.R.styleable +                .TextAppearance_elegantTextHeight); +        mElegantTextHeight = a.getBoolean(com.android.internal.R.styleable +                .TextAppearance_elegantTextHeight, false); + +        mHasLetterSpacing = a.hasValue(com.android.internal.R.styleable +                .TextAppearance_letterSpacing); +        mLetterSpacing = a.getFloat(com.android.internal.R.styleable +                .TextAppearance_letterSpacing, 0.0f); + +        mFontFeatureSettings = a.getString(com.android.internal.R.styleable +                .TextAppearance_fontFeatureSettings); + +        mFontVariationSettings = a.getString(com.android.internal.R.styleable +                .TextAppearance_fontVariationSettings); +          a.recycle();          if (colorList >= 0) { @@ -129,6 +174,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl          mTextColor = color;          mTextColorLink = linkColor;          mTypeface = null; + +        mTextFontWeight = -1; + +        mShadowRadius = 0.0f; +        mShadowDx = 0.0f; +        mShadowDy = 0.0f; +        mShadowColor = 0; + +        mHasElegantTextHeight = false; +        mElegantTextHeight = false; +        mHasLetterSpacing = false; +        mLetterSpacing = 0.0f; + +        mFontFeatureSettings = null; +        mFontVariationSettings = null;      }      public TextAppearanceSpan(Parcel src) { @@ -146,6 +206,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl              mTextColorLink = null;          }          mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src); + +        mTextFontWeight = src.readInt(); + +        mShadowRadius = src.readFloat(); +        mShadowDx = src.readFloat(); +        mShadowDy = src.readFloat(); +        mShadowColor = src.readInt(); + +        mHasElegantTextHeight = src.readBoolean(); +        mElegantTextHeight = src.readBoolean(); +        mHasLetterSpacing = src.readBoolean(); +        mLetterSpacing = src.readFloat(); + +        mFontFeatureSettings = src.readString(); +        mFontVariationSettings = src.readString();      }      public int getSpanTypeId() { @@ -183,6 +258,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl              dest.writeInt(0);          }          LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest); + +        dest.writeInt(mTextFontWeight); + +        dest.writeFloat(mShadowRadius); +        dest.writeFloat(mShadowDx); +        dest.writeFloat(mShadowDy); +        dest.writeInt(mShadowColor); + +        dest.writeBoolean(mHasElegantTextHeight); +        dest.writeBoolean(mElegantTextHeight); +        dest.writeBoolean(mHasLetterSpacing); +        dest.writeFloat(mLetterSpacing); + +        dest.writeString(mFontFeatureSettings); +        dest.writeString(mFontVariationSettings);      }      /** @@ -225,6 +315,81 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl          return mStyle;      } +    /** +     * Returns the text font weight specified by this span, or <code>-1</code> +     * if it does not specify one. +     */ +    public int getTextFontWeight() { +        return mTextFontWeight; +    } + +    /** +     * Returns the typeface specified by this span, or <code>null</code> +     * if it does not specify one. +     */ +    @Nullable +    public Typeface getTypeface() { +        return mTypeface; +    } + +    /** +     * Returns the color of the text shadow specified by this span, or <code>0</code> +     * if it does not specify one. +     */ +    public int getShadowColor() { +        return mShadowColor; +    } + +    /** +     * Returns the horizontal offset of the text shadow specified by this span, or <code>0.0f</code> +     * if it does not specify one. +     */ +    public float getShadowDx() { +        return mShadowDx; +    } + +    /** +     * Returns the vertical offset of the text shadow specified by this span, or <code>0.0f</code> +     * if it does not specify one. +     */ +    public float getShadowDy() { +        return mShadowDy; +    } + +    /** +     * Returns the blur radius of the text shadow specified by this span, or <code>0.0f</code> +     * if it does not specify one. +     */ +    public float getShadowRadius() { +        return mShadowRadius; +    } + +    /** +     * Returns the font feature settings specified by this span, or <code>null</code> +     * if it does not specify one. +     */ +    @Nullable +    public String getFontFeatureSettings() { +        return mFontFeatureSettings; +    } + +    /** +     * Returns the font variation settings specified by this span, or <code>null</code> +     * if it does not specify one. +     */ +    @Nullable +    public String getFontVariationSettings() { +        return mFontVariationSettings; +    } + +    /** +     * Returns the value of elegant height metrics flag specified by this span, +     * or <code>false</code> if it does not specify one. +     */ +    public boolean isElegantTextHeight() { +        return mElegantTextHeight; +    } +      @Override      public void updateDrawState(TextPaint ds) {          updateMeasureState(ds); @@ -236,6 +401,10 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl          if (mTextColorLink != null) {              ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0);          } + +        if (mShadowColor != 0) { +            ds.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor); +        }      }      @Override @@ -267,7 +436,16 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl          }          if (styledTypeface != null) { -            int fake = style & ~styledTypeface.getStyle(); +            final Typeface readyTypeface; +            if (mTextFontWeight >= 0) { +                final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight); +                final boolean italic = (style & Typeface.ITALIC) != 0; +                readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic)); +            } else { +                readyTypeface = styledTypeface; +            } + +            int fake = style & ~readyTypeface.getStyle();              if ((fake & Typeface.BOLD) != 0) {                  ds.setFakeBoldText(true); @@ -277,11 +455,27 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl                  ds.setTextSkewX(-0.25f);              } -            ds.setTypeface(styledTypeface); +            ds.setTypeface(readyTypeface);          }          if (mTextSize > 0) {              ds.setTextSize(mTextSize);          } + +        if (mHasElegantTextHeight) { +            ds.setElegantTextHeight(mElegantTextHeight); +        } + +        if (mHasLetterSpacing) { +            ds.setLetterSpacing(mLetterSpacing); +        } + +        if (mFontFeatureSettings != null) { +            ds.setFontFeatureSettings(mFontFeatureSettings); +        } + +        if (mFontVariationSettings != null) { +            ds.setFontVariationSettings(mFontVariationSettings); +        }      }  } diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java index d7a912057858..9fa9961d21bc 100644 --- a/core/java/android/transition/ChangeImageTransform.java +++ b/core/java/android/transition/ChangeImageTransform.java @@ -97,22 +97,13 @@ public class ChangeImageTransform extends Transition {          values.put(PROPNAME_BOUNDS, bounds);          Matrix matrix;          ImageView.ScaleType scaleType = imageView.getScaleType(); -        if (scaleType == ImageView.ScaleType.FIT_XY) { -            matrix = imageView.getImageMatrix(); -            if (!matrix.isIdentity()) { -                matrix = new Matrix(matrix); -            } else { -                int drawableWidth = drawable.getIntrinsicWidth(); -                int drawableHeight = drawable.getIntrinsicHeight(); -                if (drawableWidth > 0 && drawableHeight > 0) { -                    float scaleX = ((float) bounds.width()) / drawableWidth; -                    float scaleY = ((float) bounds.height()) / drawableHeight; -                    matrix = new Matrix(); -                    matrix.setScale(scaleX, scaleY); -                } else { -                    matrix = null; -                } -            } +        int drawableWidth = drawable.getIntrinsicWidth(); +        int drawableHeight = drawable.getIntrinsicHeight(); +        if (scaleType == ImageView.ScaleType.FIT_XY && drawableWidth > 0 && drawableHeight > 0) { +            float scaleX = ((float) bounds.width()) / drawableWidth; +            float scaleY = ((float) bounds.height()) / drawableHeight; +            matrix = new Matrix(); +            matrix.setScale(scaleX, scaleY);          } else {              matrix = new Matrix(imageView.getImageMatrix());          } @@ -152,17 +143,13 @@ public class ChangeImageTransform extends Transition {          }          Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);          Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); -        if (startBounds == null || endBounds == null) { -            return null; -        } -          Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);          Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX); +        if (startBounds == null || endBounds == null || startMatrix == null || endMatrix == null) { +            return null; +        } -        boolean matricesEqual = (startMatrix == null && endMatrix == null) || -                (startMatrix != null && startMatrix.equals(endMatrix)); - -        if (startBounds.equals(endBounds) && matricesEqual) { +        if (startBounds.equals(endBounds) && startMatrix.equals(endMatrix)) {              return null;          } @@ -172,15 +159,9 @@ public class ChangeImageTransform extends Transition {          int drawableHeight = drawable.getIntrinsicHeight();          ObjectAnimator animator; -        if (drawableWidth == 0 || drawableHeight == 0) { +        if (drawableWidth <= 0 || drawableHeight <= 0) {              animator = createNullAnimator(imageView);          } else { -            if (startMatrix == null) { -                startMatrix = Matrix.IDENTITY_MATRIX; -            } -            if (endMatrix == null) { -                endMatrix = Matrix.IDENTITY_MATRIX; -            }              ANIMATED_TRANSFORM_PROPERTY.set(imageView, startMatrix);              animator = createMatrixAnimator(imageView, startMatrix, endMatrix);          } @@ -189,7 +170,7 @@ public class ChangeImageTransform extends Transition {      private ObjectAnimator createNullAnimator(ImageView imageView) {          return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY, -                NULL_MATRIX_EVALUATOR, null, null); +                NULL_MATRIX_EVALUATOR, Matrix.IDENTITY_MATRIX, Matrix.IDENTITY_MATRIX);      }      private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix, diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index f8e8762ef592..4608e205ec7c 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -188,7 +188,13 @@ public class TransitionManager {          final ViewGroup sceneRoot = scene.getSceneRoot();          if (!sPendingTransitions.contains(sceneRoot)) { +            Scene oldScene = Scene.getCurrentScene(sceneRoot);              if (transition == null) { +                // Notify old scene that it is being exited +                if (oldScene != null) { +                    oldScene.exit(); +                } +                  scene.enter();              } else {                  sPendingTransitions.add(sceneRoot); @@ -196,7 +202,6 @@ public class TransitionManager {                  Transition transitionClone = transition.clone();                  transitionClone.setSceneRoot(sceneRoot); -                Scene oldScene = Scene.getCurrentScene(sceneRoot);                  if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {                      transitionClone.setCanRemoveViews(true);                  } diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index 5108a796a036..294a1799a2d3 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -71,19 +71,19 @@ public final class ArrayMap<K, V> implements Map<K, V> {      /**       * Maximum number of entries to have in array caches.       */ -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      private static final int CACHE_SIZE = 10;      /**       * Special hash array value that indicates the container is immutable.       */ -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      static final int[] EMPTY_IMMUTABLE_INTS = new int[0];      /**       * @hide Special immutable empty ArrayMap.       */ -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use your own singleton empty map.      public static final ArrayMap EMPTY = new ArrayMap<>(-1);      /** @@ -92,21 +92,21 @@ public final class ArrayMap<K, V> implements Map<K, V> {       * The first entry in the array is a pointer to the next array in the       * list; the second entry is a pointer to the int[] hash code array for it.       */ -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      static Object[] mBaseCache; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      static int mBaseCacheSize; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      static Object[] mTwiceBaseCache; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      static int mTwiceBaseCacheSize;      final boolean mIdentityHashCode; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use public key/value API.      int[] mHashes; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use public key/value API.      Object[] mArray; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()      int mSize;      MapCollections<K, V> mCollections; @@ -122,7 +122,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {          }      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use indexOfKey(Object).      int indexOf(Object key, int hash) {          final int N = mSize; @@ -161,7 +161,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {          return ~end;      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use indexOf(null)      int indexOfNull() {          final int N = mSize; @@ -200,7 +200,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {          return ~end;      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      private void allocArrays(final int size) {          if (mHashes == EMPTY_IMMUTABLE_INTS) {              throw new UnsupportedOperationException("ArrayMap is immutable"); @@ -239,7 +239,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {          mArray = new Object[size<<1];      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      private static void freeArrays(final int[] hashes, final Object[] array, final int size) {          if (hashes.length == (BASE_SIZE*2)) {              synchronized (ArrayMap.class) { @@ -393,8 +393,15 @@ public final class ArrayMap<K, V> implements Map<K, V> {                  : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());      } -    @UnsupportedAppUsage -    int indexOfValue(Object value) { +    /** +     * Returns an index for which {@link #valueAt} would return the +     * specified value, or a negative number if no keys map to the +     * specified value. +     * Beware that this is a linear search, unlike lookups by key, +     * and that multiple keys can map to the same value and this will +     * find only one of them. +     */ +    public int indexOfValue(Object value) {          final int N = mSize*2;          final Object[] array = mArray;          if (value == null) { @@ -551,7 +558,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {       * The array must already be large enough to contain the item.       * @hide       */ -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use put(K, V).      public void append(K key, V value) {          int index = mSize;          final int hash = key == null ? 0 diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index 526a950b4820..d74a0fe8d2c1 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -71,15 +71,15 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {      static int sTwiceBaseCacheSize;      final boolean mIdentityHashCode; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use public API.      int[] mHashes; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use public API.      Object[] mArray; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()      int mSize;      MapCollections<E, E> mCollections; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use indexOfKey(Object).      private int indexOf(Object key, int hash) {          final int N = mSize; @@ -118,7 +118,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {          return ~end;      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use indexOf(null)      private int indexOfNull() {          final int N = mSize; @@ -157,7 +157,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {          return ~end;      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      private void allocArrays(final int size) {          if (size == (BASE_SIZE * 2)) {              synchronized (ArraySet.class) { @@ -215,7 +215,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {          mArray = new Object[size];      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.      private static void freeArrays(final int[] hashes, final Object[] array, final int size) {          if (hashes.length == (BASE_SIZE * 2)) {              synchronized (ArraySet.class) { @@ -289,9 +289,10 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {          }      } -    /** {@hide} */ -    @UnsupportedAppUsage -    public ArraySet(Collection<E> set) { +    /** +     * Create a new ArraySet with items from the given collection. +     */ +    public ArraySet(Collection<? extends E> set) {          this();          if (set != null) {              addAll(set); diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index d5af92234b31..af163ac8f246 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -46,11 +46,11 @@ import libcore.util.EmptyArray;   * @hide   */  public class LongSparseLongArray implements Cloneable { -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.      private long[] mKeys; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.      private long[] mValues; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.      private int mSize;      /** diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index aa5ca3530621..89ea2d35fc2f 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -56,11 +56,11 @@ public class SparseArray<E> implements Cloneable {      private static final Object DELETED = new Object();      private boolean mGarbage = false; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)      private int[] mKeys; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, E)      private Object[] mValues; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()      private int mSize;      /** diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index 9c6b9698d1ae..d4c40954bdd1 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -185,7 +185,9 @@ public class SparseBooleanArray implements Cloneable {          return mValues[index];      } -    /** @hide */ +    /** +     * Directly set the value at a particular index. +     */      public void setValueAt(int index, boolean value) {          mValues[index] = value;      } @@ -304,10 +306,10 @@ public class SparseBooleanArray implements Cloneable {          return buffer.toString();      } -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)      private int[] mKeys; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, boolean)      private boolean[] mValues; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()      private int mSize;  } diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 19547534aef5..9e6bad1d9ae0 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -46,11 +46,11 @@ import libcore.util.EmptyArray;   * order in the case of <code>valueAt(int)</code>.</p>   */  public class SparseIntArray implements Cloneable { -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)      private int[] mKeys; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, int)      private int[] mValues; -    @UnsupportedAppUsage +    @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()      private int mSize;      /** @@ -191,7 +191,6 @@ public class SparseIntArray implements Cloneable {      /**       * Directly set the value at a particular index. -     * @hide       */      public void setValueAt(int index, int value) {          mValues[index] = value; diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index 1203541756e8..1bbef8e9cfff 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -410,7 +410,7 @@ public class ApkSignatureSchemeV2Verifier {                     NoSuchAlgorithmException {          try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {              SignatureInfo signatureInfo = findSignature(apk); -            return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo); +            return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);          }      } @@ -423,7 +423,7 @@ public class ApkSignatureSchemeV2Verifier {              if (vSigner.verityRootHash == null) {                  return null;              } -            return ApkVerityBuilder.generateApkVerityRootHash( +            return VerityBuilder.generateApkVerityRootHash(                      apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);          }      } diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index 939522dcd57f..1471870bd7d2 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -534,7 +534,7 @@ public class ApkSignatureSchemeV3Verifier {                     NoSuchAlgorithmException {          try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {              SignatureInfo signatureInfo = findSignature(apk); -            return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo); +            return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);          }      } @@ -547,7 +547,7 @@ public class ApkSignatureSchemeV3Verifier {              if (vSigner.verityRootHash == null) {                  return null;              } -            return ApkVerityBuilder.generateApkVerityRootHash( +            return VerityBuilder.generateApkVerityRootHash(                      apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);          }      } diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java index 081033ae84e9..87af5364c945 100644 --- a/core/java/android/util/apk/ApkSigningBlockUtils.java +++ b/core/java/android/util/apk/ApkSigningBlockUtils.java @@ -332,7 +332,7 @@ final class ApkSigningBlockUtils {          try {              byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,                      apk.length(), signatureInfo); -            ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerityTree(apk, +            VerityBuilder.VerityResult verity = VerityBuilder.generateApkVerityTree(apk,                      signatureInfo, new ByteBufferFactory() {                          @Override                          public ByteBuffer create(int capacity) { diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java index 553511d73670..443bbd8597af 100644 --- a/core/java/android/util/apk/ApkVerityBuilder.java +++ b/core/java/android/util/apk/VerityBuilder.java @@ -29,19 +29,18 @@ import java.security.NoSuchAlgorithmException;  import java.util.ArrayList;  /** - * ApkVerityBuilder builds the APK verity tree and the verity header.  The generated tree format can - * be stored on disk for apk-verity setup and used by kernel.  Note that since the current - * implementation is different from the upstream, we call this implementation apk-verity instead of - * fs-verity. + * VerityBuilder builds the verity Merkle tree and other metadata.  The generated tree format can + * be stored on disk for fs-verity setup and used by kernel.  The builder support standard + * fs-verity, and Android specific apk-verity that requires additional kernel patches.   * - * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to - * the existing APK format, it has to skip APK Signing Block and also has some special treatment for - * the "Central Directory offset" field of ZIP End of Central Directory. + * <p>Unlike a regular Merkle tree of fs-verity, the apk-verity tree does not cover the file content + * fully, and has to skip APK Signing Block with some special treatment for the "Central Directory + * offset" field of ZIP End of Central Directory.   *   * @hide   */ -abstract class ApkVerityBuilder { -    private ApkVerityBuilder() {} +public abstract class VerityBuilder { +    private VerityBuilder() {}      private static final int CHUNK_SIZE_BYTES = 4096;  // Typical Linux block size      private static final int DIGEST_SIZE_BYTES = 32;  // SHA-256 size @@ -51,12 +50,18 @@ abstract class ApkVerityBuilder {      private static final String JCA_DIGEST_ALGORITHM = "SHA-256";      private static final byte[] DEFAULT_SALT = new byte[8]; -    static class ApkVerityResult { +    /** Result generated by the builder. */ +    public static class VerityResult { +        /** Raw fs-verity metadata and Merkle tree ready to be deployed on disk. */          public final ByteBuffer verityData; + +        /** Size of the Merkle tree in {@code verityData}. */          public final int merkleTreeSize; + +        /** Root hash of the Merkle tree. */          public final byte[] rootHash; -        ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) { +        private VerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {              this.verityData = verityData;              this.merkleTreeSize = merkleTreeSize;              this.rootHash = rootHash; @@ -65,19 +70,48 @@ abstract class ApkVerityBuilder {      /**       * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link -     * ByteBuffer} created by the {@link ByteBufferFactory}.  The Merkle tree is suitable to be used -     * as the on-disk format for apk-verity. +     * ByteBuffer} created by the {@link ByteBufferFactory}.  The output is suitable to be used as +     * the on-disk format for fs-verity to use. +     * +     * @return VerityResult containing a buffer with the generated Merkle tree stored at the +     *         front, the tree size, and the calculated root hash. +     */ +    @NonNull +    public static VerityResult generateFsVerityTree(@NonNull RandomAccessFile apk, +            @NonNull ByteBufferFactory bufferFactory) +            throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { +        return generateVerityTreeInternal(apk, bufferFactory, null /* signatureInfo */, +                false /* skipSigningBlock */); +    } + +    /** +     * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link +     * ByteBuffer} created by the {@link ByteBufferFactory}.  The Merkle tree does not cover Signing +     * Block specificed in {@code signatureInfo}.  The output is suitable to be used as the on-disk +     * format for fs-verity to use (with elide and patch extensions).       * -     * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the +     * @return VerityResult containing a buffer with the generated Merkle tree stored at the       *         front, the tree size, and the calculated root hash.       */      @NonNull -    static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk, +    public static VerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,              @Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)              throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { -        long signingBlockSize = -                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; -        long dataSize = apk.length() - signingBlockSize; +        return generateVerityTreeInternal(apk, bufferFactory, signatureInfo, +                true /* skipSigningBlock */); +    } + +    @NonNull +    private static VerityResult generateVerityTreeInternal(@NonNull RandomAccessFile apk, +            @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo, +            boolean skipSigningBlock) +            throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { +        long dataSize = apk.length(); +        if (skipSigningBlock) { +            long signingBlockSize = +                    signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; +            dataSize -= signingBlockSize; +        }          int[] levelOffset = calculateVerityLevelOffset(dataSize);          int merkleTreeSize = levelOffset[levelOffset.length - 1]; @@ -85,11 +119,12 @@ abstract class ApkVerityBuilder {                  merkleTreeSize                  + CHUNK_SIZE_BYTES);  // maximum size of apk-verity metadata          output.order(ByteOrder.LITTLE_ENDIAN); -          ByteBuffer tree = slice(output, 0, merkleTreeSize); -        byte[] apkRootHash = generateApkVerityTreeInternal(apk, signatureInfo, DEFAULT_SALT, -                levelOffset, tree); -        return new ApkVerityResult(output, merkleTreeSize, apkRootHash); +        // Only use default salt in legacy case. +        byte[] salt = skipSigningBlock ? DEFAULT_SALT : null; +        byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset, +                tree, skipSigningBlock); +        return new VerityResult(output, merkleTreeSize, apkRootHash);      }      static void generateApkVerityFooter(@NonNull RandomAccessFile apk, @@ -138,7 +173,8 @@ abstract class ApkVerityBuilder {              throws IOException, SignatureNotFoundException, SecurityException, DigestException,                     NoSuchAlgorithmException {          try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { -            ApkVerityResult result = generateApkVerityTree(apk, signatureInfo, bufferFactory); +            VerityResult result = generateVerityTreeInternal(apk, bufferFactory, signatureInfo, +                    true /* skipSigningBlock */);              ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,                      result.verityData.limit());              generateApkVerityFooter(apk, signatureInfo, footer); @@ -170,11 +206,14 @@ abstract class ApkVerityBuilder {          private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES];          private final byte[] mSalt; -        private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException { +        private BufferedDigester(@Nullable byte[] salt, @NonNull ByteBuffer output) +                throws NoSuchAlgorithmException {              mSalt = salt;              mOutput = output.slice();              mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM); -            mMd.update(mSalt); +            if (mSalt != null) { +                mMd.update(mSalt); +            }              mBytesDigestedSinceReset = 0;          } @@ -201,7 +240,9 @@ abstract class ApkVerityBuilder {                      mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);                      mOutput.put(mDigestBuffer);                      // After digest, MessageDigest resets automatically, so no need to reset again. -                    mMd.update(mSalt); +                    if (mSalt != null) { +                        mMd.update(mSalt); +                    }                      mBytesDigestedSinceReset = 0;                  }              } @@ -242,6 +283,26 @@ abstract class ApkVerityBuilder {      // thus the syscall overhead is not too big.      private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024; +    private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output) +            throws IOException, NoSuchAlgorithmException, DigestException { +        BufferedDigester digester = new BufferedDigester(null /* salt */, output); + +        // 1. Digest the whole file by chunks. +        consumeByChunk(digester, +                new MemoryMappedFileDataSource(file.getFD(), 0, file.length()), +                MMAP_REGION_SIZE_BYTES); + +        // 2. Pad 0s up to the nearest 4096-byte block before hashing. +        int lastIncompleteChunkSize = (int) (file.length() % CHUNK_SIZE_BYTES); +        if (lastIncompleteChunkSize != 0) { +            digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize)); +        } +        digester.assertEmptyBuffer(); + +        // 3. Fill up the rest of buffer with 0s. +        digester.fillUpLastOutputChunk(); +    } +      private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,              SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)              throws IOException, NoSuchAlgorithmException, DigestException { @@ -288,15 +349,19 @@ abstract class ApkVerityBuilder {      }      @NonNull -    private static byte[] generateApkVerityTreeInternal(@NonNull RandomAccessFile apk, -            @Nullable SignatureInfo signatureInfo, @NonNull byte[] salt, -            @NonNull int[] levelOffset, @NonNull ByteBuffer output) +    private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk, +            @Nullable SignatureInfo signatureInfo, @Nullable byte[] salt, +            @NonNull int[] levelOffset, @NonNull ByteBuffer output, boolean skipSigningBlock)              throws IOException, NoSuchAlgorithmException, DigestException { -        assertSigningBlockAlignedAndHasFullPages(signatureInfo); -          // 1. Digest the apk to generate the leaf level hashes. -        generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output, -                    levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); +        if (skipSigningBlock) { +            assertSigningBlockAlignedAndHasFullPages(signatureInfo); +            generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output, +                        levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); +        } else { +            generateFsVerityDigestAtLeafLevel(apk, slice(output, +                        levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); +        }          // 2. Digest the lower level hashes bottom up.          for (int level = levelOffset.length - 3; level >= 0; level--) { @@ -434,10 +499,11 @@ abstract class ApkVerityBuilder {          return levelOffset;      } -    private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) { +    private static void assertSigningBlockAlignedAndHasFullPages( +            @NonNull SignatureInfo signatureInfo) {          if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {              throw new IllegalArgumentException( -                    "APK Signing Block does not start at the page  boundary: " +                    "APK Signing Block does not start at the page boundary: "                      + signatureInfo.apkSigningBlockOffset);          } diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index 4b946d7f430f..667fab5537c9 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -19,6 +19,7 @@ package android.view;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.UnsupportedAppUsage; +import android.graphics.BaseRecordingCanvas;  import android.graphics.Bitmap;  import android.graphics.CanvasProperty;  import android.graphics.Paint; @@ -35,7 +36,7 @@ import dalvik.annotation.optimization.FastNative;   *   * @hide   */ -public final class DisplayListCanvas extends RecordingCanvas { +public final class DisplayListCanvas extends BaseRecordingCanvas {      // The recording canvas pool should be large enough to handle a deeply nested      // view hierarchy because display lists are generated recursively.      private static final int POOL_LIMIT = 25; diff --git a/core/java/android/view/NativeVectorDrawableAnimator.java b/core/java/android/view/NativeVectorDrawableAnimator.java new file mode 100644 index 000000000000..b0556a3f8a91 --- /dev/null +++ b/core/java/android/view/NativeVectorDrawableAnimator.java @@ -0,0 +1,29 @@ +/* + * 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.view; + +/** + * Exists just to allow for android.graphics & android.view package separation + * + * TODO: Get off of this coupling more cleanly somehow + * + * @hide + */ +public interface NativeVectorDrawableAnimator { +    /** @hide */ +    long getAnimatorNativePtr(); +} diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 982e5c2a6924..8ae912762fdb 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -24,7 +24,6 @@ import android.graphics.Matrix;  import android.graphics.Outline;  import android.graphics.Paint;  import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable;  import dalvik.annotation.optimization.CriticalNative;  import dalvik.annotation.optimization.FastNative; @@ -148,12 +147,12 @@ public class RenderNode {       * @hide       */      final long mNativeRenderNode; -    private final View mOwningView; +    private final AnimationHost mAnimationHost; -    private RenderNode(String name, View owningView) { +    private RenderNode(String name, AnimationHost animationHost) {          mNativeRenderNode = nCreate(name);          NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode); -        mOwningView = owningView; +        mAnimationHost = animationHost;      }      /** @@ -162,7 +161,7 @@ public class RenderNode {      private RenderNode(long nativePtr) {          mNativeRenderNode = nativePtr;          NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode); -        mOwningView = null; +        mAnimationHost = null;      }      /** @@ -174,8 +173,8 @@ public class RenderNode {       * @return A new RenderNode.       */      @UnsupportedAppUsage -    public static RenderNode create(String name, @Nullable View owningView) { -        return new RenderNode(name, owningView); +    public static RenderNode create(String name, @Nullable AnimationHost animationHost) { +        return new RenderNode(name, animationHost);      }      /** @@ -189,10 +188,37 @@ public class RenderNode {      }      /** +     * Listens for RenderNode position updates for synchronous window movement. +     * +     * This is not suitable for generic position listening, it is only designed & intended +     * for use by things which require external position events like SurfaceView, PopupWindow, etc.. +     * +     * @hide +     */ +    interface PositionUpdateListener { + +        /** +         * Called by native by a Rendering Worker thread to update window position +         * +         * @hide +         */ +        void positionChanged(long frameNumber, int left, int top, int right, int bottom); + +        /** +         * Called by native on RenderThread to notify that the view is no longer in the +         * draw tree. UI thread is blocked at this point. +         * +         * @hide +         */ +        void positionLost(long frameNumber); + +    } + +    /**       * Enable callbacks for position changes.       */ -    public void requestPositionUpdates(SurfaceView view) { -        nRequestPositionUpdates(mNativeRenderNode, view); +    public void requestPositionUpdates(PositionUpdateListener listener) { +        nRequestPositionUpdates(mNativeRenderNode, listener);      } @@ -873,26 +899,42 @@ public class RenderNode {      // Animations      /////////////////////////////////////////////////////////////////////////// +    /** +     * TODO: Figure out if this can be eliminated/refactored away +     * +     * For now this interface exists to de-couple RenderNode from anything View-specific in a +     * bit of a kludge. +     * +     * @hide */ +    interface AnimationHost { +        void registerAnimatingRenderNode(RenderNode animator); +        void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator); +        boolean isAttached(); +    } + +    /** @hide */      public void addAnimator(RenderNodeAnimator animator) { -        if (mOwningView == null || mOwningView.mAttachInfo == null) { +        if (!isAttached()) {              throw new IllegalStateException("Cannot start this animator on a detached view!");          }          nAddAnimator(mNativeRenderNode, animator.getNativeAnimator()); -        mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); +        mAnimationHost.registerAnimatingRenderNode(this);      } +    /** @hide */      public boolean isAttached() { -        return mOwningView != null && mOwningView.mAttachInfo != null; +        return mAnimationHost != null && mAnimationHost.isAttached();      } -    public void registerVectorDrawableAnimator( -            AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { -        if (mOwningView == null || mOwningView.mAttachInfo == null) { +    /** @hide */ +    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animatorSet) { +        if (!isAttached()) {              throw new IllegalStateException("Cannot start this animator on a detached view!");          } -        mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet); +        mAnimationHost.registerVectorDrawableAnimator(animatorSet);      } +    /** @hide */      public void endAllAnimators() {          nEndAllAnimators(mNativeRenderNode);      } @@ -906,7 +948,8 @@ public class RenderNode {      private static native long nGetNativeFinalizer();      private static native void nOutput(long renderNode);      private static native int nGetDebugSize(long renderNode); -    private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback); +    private static native void nRequestPositionUpdates(long renderNode, +            PositionUpdateListener callback);      // Animations diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 514a11ebf713..e71182c33c12 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -209,7 +209,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb      public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {          super(context, attrs, defStyleAttr, defStyleRes); -        mRenderNode.requestPositionUpdates(this); +        mRenderNode.requestPositionUpdates(mPositionListener);          setWillNotDraw(true);      } @@ -826,81 +826,80 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb      private Rect mRTLastReportedPosition = new Rect(); -    /** -     * Called by native by a Rendering Worker thread to update the window position -     * @hide -     */ -    @UnsupportedAppUsage -    public final void updateSurfacePosition_renderWorker(long frameNumber, -            int left, int top, int right, int bottom) { -        if (mSurfaceControl == null) { -            return; -        } +    private RenderNode.PositionUpdateListener mPositionListener = +            new RenderNode.PositionUpdateListener() { -        // TODO: This is teensy bit racey in that a brand new SurfaceView moving on -        // its 2nd frame if RenderThread is running slowly could potentially see -        // this as false, enter the branch, get pre-empted, then this comes along -        // and reports a new position, then the UI thread resumes and reports -        // its position. This could therefore be de-sync'd in that interval, but -        // the synchronization would violate the rule that RT must never block -        // on the UI thread which would open up potential deadlocks. The risk of -        // a single-frame desync is therefore preferable for now. -        mRtHandlingPositionUpdates = true; -        if (mRTLastReportedPosition.left == left -                && mRTLastReportedPosition.top == top -                && mRTLastReportedPosition.right == right -                && mRTLastReportedPosition.bottom == bottom) { -            return; -        } -        try { -            if (DEBUG) { -                Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " + -                        "postion = [%d, %d, %d, %d]", System.identityHashCode(this), -                        frameNumber, left, top, right, bottom)); +        @Override +        public void positionChanged(long frameNumber, int left, int top, int right, int bottom) { +            if (mSurfaceControl == null) { +                return;              } -            mRTLastReportedPosition.set(left, top, right, bottom); -            setParentSpaceRectangle(mRTLastReportedPosition, frameNumber); -            // Now overwrite mRTLastReportedPosition with our values -        } catch (Exception ex) { -            Log.e(TAG, "Exception from repositionChild", ex); -        } -    } -    /** -     * Called by native on RenderThread to notify that the view is no longer in the -     * draw tree. UI thread is blocked at this point. -     * @hide -     */ -    @UnsupportedAppUsage -    public final void surfacePositionLost_uiRtSync(long frameNumber) { -        if (DEBUG) { -            Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d", -                    System.identityHashCode(this), frameNumber)); +            // TODO: This is teensy bit racey in that a brand new SurfaceView moving on +            // its 2nd frame if RenderThread is running slowly could potentially see +            // this as false, enter the branch, get pre-empted, then this comes along +            // and reports a new position, then the UI thread resumes and reports +            // its position. This could therefore be de-sync'd in that interval, but +            // the synchronization would violate the rule that RT must never block +            // on the UI thread which would open up potential deadlocks. The risk of +            // a single-frame desync is therefore preferable for now. +            mRtHandlingPositionUpdates = true; +            if (mRTLastReportedPosition.left == left +                    && mRTLastReportedPosition.top == top +                    && mRTLastReportedPosition.right == right +                    && mRTLastReportedPosition.bottom == bottom) { +                return; +            } +            try { +                if (DEBUG) { +                    Log.d(TAG, String.format( +                            "%d updateSurfacePosition RenderWorker, frameNr = %d, " +                                    + "postion = [%d, %d, %d, %d]", +                            System.identityHashCode(this), frameNumber, +                            left, top, right, bottom)); +                } +                mRTLastReportedPosition.set(left, top, right, bottom); +                setParentSpaceRectangle(mRTLastReportedPosition, frameNumber); +                // Now overwrite mRTLastReportedPosition with our values +            } catch (Exception ex) { +                Log.e(TAG, "Exception from repositionChild", ex); +            }          } -        mRTLastReportedPosition.setEmpty(); -        if (mSurfaceControl == null) { -            return; -        } -        if (mRtHandlingPositionUpdates) { -            mRtHandlingPositionUpdates = false; -            // This callback will happen while the UI thread is blocked, so we can -            // safely access other member variables at this time. -            // So do what the UI thread would have done if RT wasn't handling position -            // updates. -            if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) { -                try { -                    if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " + -                            "postion = [%d, %d, %d, %d]", System.identityHashCode(this), -                            mScreenRect.left, mScreenRect.top, -                            mScreenRect.right, mScreenRect.bottom)); -                    setParentSpaceRectangle(mScreenRect, frameNumber); -                } catch (Exception ex) { -                    Log.e(TAG, "Exception configuring surface", ex); +        @Override +        public void positionLost(long frameNumber) { +            if (DEBUG) { +                Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d", +                        System.identityHashCode(this), frameNumber)); +            } +            mRTLastReportedPosition.setEmpty(); + +            if (mSurfaceControl == null) { +                return; +            } +            if (mRtHandlingPositionUpdates) { +                mRtHandlingPositionUpdates = false; +                // This callback will happen while the UI thread is blocked, so we can +                // safely access other member variables at this time. +                // So do what the UI thread would have done if RT wasn't handling position +                // updates. +                if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) { +                    try { +                        if (DEBUG) { +                            Log.d(TAG, String.format("%d updateSurfacePosition, " +                                            + "postion = [%d, %d, %d, %d]", +                                    System.identityHashCode(this), +                                    mScreenRect.left, mScreenRect.top, +                                    mScreenRect.right, mScreenRect.bottom)); +                        } +                        setParentSpaceRectangle(mScreenRect, frameNumber); +                    } catch (Exception ex) { +                        Log.e(TAG, "Exception configuring surface", ex); +                    }                  }              }          } -    } +    };      private SurfaceHolder.Callback[] getSurfaceCallbacks() {          SurfaceHolder.Callback callbacks[]; diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 6737839993ed..42690cef9da3 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -25,7 +25,6 @@ import android.content.res.TypedArray;  import android.graphics.Bitmap;  import android.graphics.Point;  import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable;  import android.os.IBinder;  import android.os.ParcelFileDescriptor;  import android.os.RemoteException; @@ -914,8 +913,7 @@ public final class ThreadedRenderer {          nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);      } -    void registerVectorDrawableAnimator( -        AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { +    void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {          nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,                  animator.getAnimatorNativePtr());      } @@ -976,6 +974,25 @@ public final class ThreadedRenderer {          }      } +    /** The root of everything */ +    public @NonNull RenderNode getRootNode() { +        return mRootNode; +    } + +    private boolean mForceDark = false; + +    /** +     * Whether or not the force-dark feature should be used for this renderer. +     */ +    public boolean setForceDark(boolean enable) { +        if (mForceDark != enable) { +            mForceDark = enable; +            nSetForceDark(mNativeProxy, enable); +            return true; +        } +        return false; +    } +      /**       * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.       * TODO: deduplicate against ThreadedRenderer. @@ -1255,4 +1272,5 @@ public final class ThreadedRenderer {      private static native void nSetIsolatedProcess(boolean enabled);      private static native void nSetContextPriority(int priority);      private static native void nAllocateBuffers(long nativeProxy, Surface window); +    private static native void nSetForceDark(long nativeProxy, boolean enabled);  } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f4be9f2d7949..b2944d6a9923 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4864,7 +4864,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,          setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);          mUserPaddingStart = UNDEFINED_PADDING;          mUserPaddingEnd = UNDEFINED_PADDING; -        mRenderNode = RenderNode.create(getClass().getName(), this); +        mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));          if (!sCompatibilityDone && context != null) {              final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; @@ -5732,7 +5732,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,      @UnsupportedAppUsage      View() {          mResources = null; -        mRenderNode = RenderNode.create(getClass().getName(), this); +        mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));      }      final boolean debugDraw() { @@ -15255,6 +15255,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,       * a value of 'true' will not override any 'false' value in its parent chain nor will       * it prevent any 'false' in any of its children.       * +     * The default behavior of force dark is also influenced by the Theme's +     * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. +     * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. +     *       * @param allow Whether or not to allow force dark.       *       * @hide @@ -15632,7 +15636,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,      /**       * Sets the visual z position of this view, in pixels. This is equivalent to setting the       * {@link #setTranslationZ(float) translationZ} property to be the difference between -     * the x value passed in and the current {@link #getElevation() elevation} property. +     * the z value passed in and the current {@link #getElevation() elevation} property.       *       * @param z The visual z position of this view, in pixels.       */ @@ -20600,7 +20604,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,       */      private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {          if (renderNode == null) { -            renderNode = RenderNode.create(drawable.getClass().getName(), this); +            renderNode = RenderNode.create(drawable.getClass().getName(), +                    new ViewAnimationHostBridge(this));              renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND);          } diff --git a/core/java/android/view/ViewAnimationHostBridge.java b/core/java/android/view/ViewAnimationHostBridge.java new file mode 100644 index 000000000000..58f555dfa305 --- /dev/null +++ b/core/java/android/view/ViewAnimationHostBridge.java @@ -0,0 +1,48 @@ +/* + * 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.view; + +/** + * Maps a View to a RenderNode's AnimationHost + * + * @hide + */ +public class ViewAnimationHostBridge implements RenderNode.AnimationHost { +    private final View mView; + +    /** +     * @param view the View to bridge to an AnimationHost +     */ +    public ViewAnimationHostBridge(View view) { +        mView = view; +    } + +    @Override +    public void registerAnimatingRenderNode(RenderNode animator) { +        mView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(animator); +    } + +    @Override +    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { +        mView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animator); +    } + +    @Override +    public boolean isAttached() { +        return mView.mAttachInfo != null; +    } +} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2ee7ab939bd9..bef8e8fedfdf 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -43,6 +43,7 @@ import android.content.pm.PackageManager;  import android.content.res.CompatibilityInfo;  import android.content.res.Configuration;  import android.content.res.Resources; +import android.content.res.TypedArray;  import android.graphics.Canvas;  import android.graphics.Color;  import android.graphics.Matrix; @@ -52,7 +53,6 @@ import android.graphics.PointF;  import android.graphics.PorterDuff;  import android.graphics.Rect;  import android.graphics.Region; -import android.graphics.drawable.AnimatedVectorDrawable;  import android.graphics.drawable.Drawable;  import android.hardware.display.DisplayManager;  import android.hardware.display.DisplayManager.DisplayListener; @@ -239,6 +239,12 @@ public final class ViewRootImpl implements ViewParent,      final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();      @UnsupportedAppUsage      final Context mContext; +    /** +     * TODO(b/116349163): Check if we can merge this into {@link #mContext}. +     */ +    @NonNull +    private Context mDisplayContext; +      @UnsupportedAppUsage      final IWindowSession mWindowSession;      @NonNull Display mDisplay; @@ -532,6 +538,7 @@ public final class ViewRootImpl implements ViewParent,      public ViewRootImpl(Context context, Display display) {          mContext = context; +        mDisplayContext = context.createDisplayContext(display);          mWindowSession = WindowManagerGlobal.getWindowSession();          mDisplay = display;          mBasePackageName = context.getBasePackageName(); @@ -984,6 +991,9 @@ public final class ViewRootImpl implements ViewParent,          ThreadedRenderer.invokeFunctor(functor, waitForCompletion);      } +    /** +     * @param animator animator to register with the hardware renderer +     */      public void registerAnimatingRenderNode(RenderNode animator) {          if (mAttachInfo.mThreadedRenderer != null) {              mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator); @@ -995,8 +1005,10 @@ public final class ViewRootImpl implements ViewParent,          }      } -    public void registerVectorDrawableAnimator( -            AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { +    /** +     * @param animator animator to register with the hardware renderer +     */ +    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {          if (mAttachInfo.mThreadedRenderer != null) {              mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);          } @@ -1066,6 +1078,7 @@ public final class ViewRootImpl implements ViewParent,                  mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,                          attrs.getTitle().toString());                  mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut); +                updateForceDarkMode();                  if (mAttachInfo.mThreadedRenderer != null) {                      mAttachInfo.mHardwareAccelerated =                              mAttachInfo.mHardwareAccelerationRequested = true; @@ -1074,6 +1087,27 @@ public final class ViewRootImpl implements ViewParent,          }      } +    private int getNightMode() { +        return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; +    } + +    private void updateForceDarkMode() { +        if (mAttachInfo.mThreadedRenderer == null) return; + +        boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES; +        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme); +        boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false); +        a.recycle(); + +        boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode); +        changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme); + +        if (changed) { +            // TODO: Don't require regenerating all display lists to apply this setting +            invalidateWorld(mView); +        } +    } +      @UnsupportedAppUsage      public View getView() {          return mView; @@ -1249,6 +1283,7 @@ public final class ViewRootImpl implements ViewParent,          } else {              mDisplay = preferredDisplay;          } +        mDisplayContext = mContext.createDisplayContext(mDisplay);      }      void pokeDrawLockIfNeeded() { @@ -2579,7 +2614,7 @@ public final class ViewRootImpl implements ViewParent,                      .mayUseInputMethod(mWindowAttributes.flags);              if (imTarget != mLastWasImTarget) {                  mLastWasImTarget = imTarget; -                InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); +                InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);                  if (imm != null && imTarget) {                      imm.onPreWindowFocus(mView, hasWindowFocus);                      imm.onPostWindowFocus(mView, mView.findFocus(), @@ -2695,7 +2730,7 @@ public final class ViewRootImpl implements ViewParent,              mLastWasImTarget = WindowManager.LayoutParams                      .mayUseInputMethod(mWindowAttributes.flags); -            InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); +            InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);              if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {                  imm.onPreWindowFocus(mView, hasWindowFocus);              } @@ -4065,6 +4100,8 @@ public final class ViewRootImpl implements ViewParent,              mForceNextWindowRelayout = true;              requestLayout();          } + +        updateForceDarkMode();      }      /** @@ -4329,7 +4366,8 @@ public final class ViewRootImpl implements ViewParent,                      enqueueInputEvent(event, null, 0, true);                  } break;                  case MSG_CHECK_FOCUS: { -                    InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); +                    InputMethodManager imm = +                            mDisplayContext.getSystemService(InputMethodManager.class);                      if (imm != null) {                          imm.checkFocus();                      } @@ -4871,7 +4909,7 @@ public final class ViewRootImpl implements ViewParent,          @Override          protected int onProcess(QueuedInputEvent q) {              if (mLastWasImTarget && !isInLocalFocusMode()) { -                InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); +                InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);                  if (imm != null) {                      final InputEvent event = q.mEvent;                      if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event); diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index 87b7b057e668..0e1f7675c8c3 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -203,11 +203,6 @@ public abstract class Animation implements Cloneable {       */      private float mScaleFactor = 1f; -    /** -     * Don't animate the wallpaper. -     */ -    private boolean mDetachWallpaper = false; -      private boolean mShowWallpaper;      private boolean mMore = true; @@ -667,9 +662,10 @@ public abstract class Animation implements Cloneable {       *       * @param detachWallpaper true if the wallpaper should be detached from the animation       * @attr ref android.R.styleable#Animation_detachWallpaper +     * +     * @deprecated All window animations are running with detached wallpaper.       */      public void setDetachWallpaper(boolean detachWallpaper) { -        mDetachWallpaper = detachWallpaper;      }      /** @@ -793,9 +789,11 @@ public abstract class Animation implements Cloneable {      /**       * Return value of {@link #setDetachWallpaper(boolean)}.       * @attr ref android.R.styleable#Animation_detachWallpaper +     * +     * @deprecated All window animations are running with detached wallpaper.       */      public boolean getDetachWallpaper() { -        return mDetachWallpaper; +        return false;      }      /** diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index e1600c4a92c8..d09323d3f8ad 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -124,7 +124,8 @@ public interface InputMethod {       * @hide       */      @MainThread -    public void updateInputMethodDisplay(int displayId); +    default void updateInputMethodDisplay(int displayId) { +    }      /**       * Bind a new application environment in to the input method, so that it diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 29339e915ce0..3e240cfdb69f 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy;  import com.android.internal.util.IndentingPrintWriter;  import com.android.internal.util.Preconditions; +import com.google.android.textclassifier.AnnotatorModel; +  import java.io.File;  import java.io.FileNotFoundException;  import java.io.IOException; @@ -92,7 +94,7 @@ public final class TextClassifierImpl implements TextClassifier {      @GuardedBy("mLock") // Do not access outside this lock.      private ModelFile mModel;      @GuardedBy("mLock") // Do not access outside this lock. -    private TextClassifierImplNative mNative; +    private AnnotatorModel mNative;      private final Object mLoggerLock = new Object();      @GuardedBy("mLoggerLock") // Do not access outside this lock. @@ -125,7 +127,7 @@ public final class TextClassifierImpl implements TextClassifier {                      && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {                  final String localesString = concatenateLocales(request.getDefaultLocales());                  final ZonedDateTime refTime = ZonedDateTime.now(); -                final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales()); +                final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());                  final int start;                  final int end;                  if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) { @@ -134,7 +136,7 @@ public final class TextClassifierImpl implements TextClassifier {                  } else {                      final int[] startEnd = nativeImpl.suggestSelection(                              string, request.getStartIndex(), request.getEndIndex(), -                            new TextClassifierImplNative.SelectionOptions(localesString)); +                            new AnnotatorModel.SelectionOptions(localesString));                      start = startEnd[0];                      end = startEnd[1];                  } @@ -142,10 +144,10 @@ public final class TextClassifierImpl implements TextClassifier {                          && start >= 0 && end <= string.length()                          && start <= request.getStartIndex() && end >= request.getEndIndex()) {                      final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end); -                    final TextClassifierImplNative.ClassificationResult[] results = +                    final AnnotatorModel.ClassificationResult[] results =                              nativeImpl.classifyText(                                      string, start, end, -                                    new TextClassifierImplNative.ClassificationOptions( +                                    new AnnotatorModel.ClassificationOptions(                                              refTime.toInstant().toEpochMilli(),                                              refTime.getZone().getId(),                                              localesString)); @@ -184,11 +186,11 @@ public final class TextClassifierImpl implements TextClassifier {                  final String localesString = concatenateLocales(request.getDefaultLocales());                  final ZonedDateTime refTime = request.getReferenceTime() != null                          ? request.getReferenceTime() : ZonedDateTime.now(); -                final TextClassifierImplNative.ClassificationResult[] results = +                final AnnotatorModel.ClassificationResult[] results =                          getNative(request.getDefaultLocales())                                  .classifyText(                                          string, request.getStartIndex(), request.getEndIndex(), -                                        new TextClassifierImplNative.ClassificationOptions( +                                        new AnnotatorModel.ClassificationOptions(                                                  refTime.toInstant().toEpochMilli(),                                                  refTime.getZone().getId(),                                                  localesString)); @@ -228,17 +230,17 @@ public final class TextClassifierImpl implements TextClassifier {                      ? request.getEntityConfig().resolveEntityListModifications(                              getEntitiesForHints(request.getEntityConfig().getHints()))                      : mSettings.getEntityListDefault(); -            final TextClassifierImplNative nativeImpl = +            final AnnotatorModel nativeImpl =                      getNative(request.getDefaultLocales()); -            final TextClassifierImplNative.AnnotatedSpan[] annotations = +            final AnnotatorModel.AnnotatedSpan[] annotations =                      nativeImpl.annotate(                          textString, -                        new TextClassifierImplNative.AnnotationOptions( +                        new AnnotatorModel.AnnotationOptions(                                  refTime.toInstant().toEpochMilli(),                                          refTime.getZone().getId(),                                  concatenateLocales(request.getDefaultLocales()))); -            for (TextClassifierImplNative.AnnotatedSpan span : annotations) { -                final TextClassifierImplNative.ClassificationResult[] results = +            for (AnnotatorModel.AnnotatedSpan span : annotations) { +                final AnnotatorModel.ClassificationResult[] results =                          span.getClassification();                  if (results.length == 0                          || !entitiesToIdentify.contains(results[0].getCollection())) { @@ -297,7 +299,7 @@ public final class TextClassifierImpl implements TextClassifier {          }      } -    private TextClassifierImplNative getNative(LocaleList localeList) +    private AnnotatorModel getNative(LocaleList localeList)              throws FileNotFoundException {          synchronized (mLock) {              localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList; @@ -310,7 +312,7 @@ public final class TextClassifierImpl implements TextClassifier {                  destroyNativeIfExistsLocked();                  final ParcelFileDescriptor fd = ParcelFileDescriptor.open(                          new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY); -                mNative = new TextClassifierImplNative(fd.getFd()); +                mNative = new AnnotatorModel(fd.getFd());                  closeAndLogError(fd);                  mModel = bestModel;              } @@ -398,14 +400,14 @@ public final class TextClassifierImpl implements TextClassifier {      }      private TextClassification createClassificationResult( -            TextClassifierImplNative.ClassificationResult[] classifications, +            AnnotatorModel.ClassificationResult[] classifications,              String text, int start, int end, @Nullable Instant referenceTime) {          final String classifiedText = text.substring(start, end);          final TextClassification.Builder builder = new TextClassification.Builder()                  .setText(classifiedText);          final int size = classifications.length; -        TextClassifierImplNative.ClassificationResult highestScoringResult = null; +        AnnotatorModel.ClassificationResult highestScoringResult = null;          float highestScore = Float.MIN_VALUE;          for (int i = 0; i < size; i++) {              builder.setEntityType(classifications[i].getCollection(), @@ -486,9 +488,9 @@ public final class TextClassifierImpl implements TextClassifier {              try {                  final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(                          file, ParcelFileDescriptor.MODE_READ_ONLY); -                final int version = TextClassifierImplNative.getVersion(modelFd.getFd()); +                final int version = AnnotatorModel.getVersion(modelFd.getFd());                  final String supportedLocalesStr = -                        TextClassifierImplNative.getLocales(modelFd.getFd()); +                        AnnotatorModel.getLocales(modelFd.getFd());                  if (supportedLocalesStr.isEmpty()) {                      Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());                      return null; @@ -676,7 +678,7 @@ public final class TextClassifierImpl implements TextClassifier {          public static List<LabeledIntent> create(                  Context context,                  @Nullable Instant referenceTime, -                TextClassifierImplNative.ClassificationResult classification, +                AnnotatorModel.ClassificationResult classification,                  String text) {              final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);              text = text.trim(); diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java deleted file mode 100644 index 3d4c8f2863ea..000000000000 --- a/core/java/android/view/textclassifier/TextClassifierImplNative.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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.view.textclassifier; - -import android.content.res.AssetFileDescriptor; - -/** - * Java wrapper for TextClassifier native library interface. This library is used for detecting - * entities in text. - */ -final class TextClassifierImplNative { - -    static { -        System.loadLibrary("textclassifier"); -    } - -    private final long mModelPtr; - -    /** -     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as -     * a file descriptor. -     */ -    TextClassifierImplNative(int fd) { -        mModelPtr = nativeNew(fd); -        if (mModelPtr == 0L) { -            throw new IllegalArgumentException("Couldn't initialize TC from file descriptor."); -        } -    } - -    /** -     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as -     * a file path. -     */ -    TextClassifierImplNative(String path) { -        mModelPtr = nativeNewFromPath(path); -        if (mModelPtr == 0L) { -            throw new IllegalArgumentException("Couldn't initialize TC from given file."); -        } -    } - -    /** -     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as -     * an AssetFileDescriptor. -     */ -    TextClassifierImplNative(AssetFileDescriptor afd) { -        mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength()); -        if (mModelPtr == 0L) { -            throw new IllegalArgumentException( -                    "Couldn't initialize TC from given AssetFileDescriptor"); -        } -    } - -    /** -     * Given a string context and current selection, computes the SmartSelection suggestion. -     * -     * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is -     * the character index where the selection begins, and selectionEnd is the index of one -     * character past the selection span. -     * -     * <p>The return value is an array of two ints: suggested selection beginning and end, with the -     * same semantics as the input selectionBeginning and selectionEnd. -     */ -    public int[] suggestSelection( -            String context, int selectionBegin, int selectionEnd, SelectionOptions options) { -        return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options); -    } - -    /** -     * Given a string context and current selection, classifies the type of the selected text. -     * -     * <p>The begin and end params are character indices in the context string. -     * -     * <p>Returns an array of ClassificationResult objects with the probability scores for different -     * collections. -     */ -    public ClassificationResult[] classifyText( -            String context, int selectionBegin, int selectionEnd, ClassificationOptions options) { -        return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options); -    } - -    /** -     * Annotates given input text. The annotations should cover the whole input context except for -     * whitespaces, and are sorted by their position in the context string. -     */ -    public AnnotatedSpan[] annotate(String text, AnnotationOptions options) { -        return nativeAnnotate(mModelPtr, text, options); -    } - -    /** Frees up the allocated memory. */ -    public void close() { -        nativeClose(mModelPtr); -    } - -    /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */ -    public static String getLocales(int fd) { -        return nativeGetLocales(fd); -    } - -    /** Returns the version of the model. */ -    public static int getVersion(int fd) { -        return nativeGetVersion(fd); -    } - -    /** Represents a datetime parsing result from classifyText calls. */ -    public static final class DatetimeResult { -        static final int GRANULARITY_YEAR = 0; -        static final int GRANULARITY_MONTH = 1; -        static final int GRANULARITY_WEEK = 2; -        static final int GRANULARITY_DAY = 3; -        static final int GRANULARITY_HOUR = 4; -        static final int GRANULARITY_MINUTE = 5; -        static final int GRANULARITY_SECOND = 6; - -        private final long mTimeMsUtc; -        private final int mGranularity; - -        DatetimeResult(long timeMsUtc, int granularity) { -            mGranularity = granularity; -            mTimeMsUtc = timeMsUtc; -        } - -        public long getTimeMsUtc() { -            return mTimeMsUtc; -        } - -        public int getGranularity() { -            return mGranularity; -        } -    } - -    /** Represents a result of classifyText method call. */ -    public static final class ClassificationResult { -        private final String mCollection; -        private final float mScore; -        private final DatetimeResult mDatetimeResult; - -        ClassificationResult( -                String collection, float score, DatetimeResult datetimeResult) { -            mCollection = collection; -            mScore = score; -            mDatetimeResult = datetimeResult; -        } - -        public String getCollection() { -            if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) { -                switch (mDatetimeResult.getGranularity()) { -                    case DatetimeResult.GRANULARITY_HOUR: -                        // fall through -                    case DatetimeResult.GRANULARITY_MINUTE: -                        // fall through -                    case DatetimeResult.GRANULARITY_SECOND: -                        return TextClassifier.TYPE_DATE_TIME; -                    default: -                        return TextClassifier.TYPE_DATE; -                } -            } -            return mCollection; -        } - -        public float getScore() { -            return mScore; -        } - -        public DatetimeResult getDatetimeResult() { -            return mDatetimeResult; -        } -    } - -    /** Represents a result of Annotate call. */ -    public static final class AnnotatedSpan { -        private final int mStartIndex; -        private final int mEndIndex; -        private final ClassificationResult[] mClassification; - -        AnnotatedSpan( -                int startIndex, int endIndex, ClassificationResult[] classification) { -            mStartIndex = startIndex; -            mEndIndex = endIndex; -            mClassification = classification; -        } - -        public int getStartIndex() { -            return mStartIndex; -        } - -        public int getEndIndex() { -            return mEndIndex; -        } - -        public ClassificationResult[] getClassification() { -            return mClassification; -        } -    } - -    /** Represents options for the suggestSelection call. */ -    public static final class SelectionOptions { -        private final String mLocales; - -        SelectionOptions(String locales) { -            mLocales = locales; -        } - -        public String getLocales() { -            return mLocales; -        } -    } - -    /** Represents options for the classifyText call. */ -    public static final class ClassificationOptions { -        private final long mReferenceTimeMsUtc; -        private final String mReferenceTimezone; -        private final String mLocales; - -        ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { -            mReferenceTimeMsUtc = referenceTimeMsUtc; -            mReferenceTimezone = referenceTimezone; -            mLocales = locale; -        } - -        public long getReferenceTimeMsUtc() { -            return mReferenceTimeMsUtc; -        } - -        public String getReferenceTimezone() { -            return mReferenceTimezone; -        } - -        public String getLocale() { -            return mLocales; -        } -    } - -    /** Represents options for the Annotate call. */ -    public static final class AnnotationOptions { -        private final long mReferenceTimeMsUtc; -        private final String mReferenceTimezone; -        private final String mLocales; - -        AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { -            mReferenceTimeMsUtc = referenceTimeMsUtc; -            mReferenceTimezone = referenceTimezone; -            mLocales = locale; -        } - -        public long getReferenceTimeMsUtc() { -            return mReferenceTimeMsUtc; -        } - -        public String getReferenceTimezone() { -            return mReferenceTimezone; -        } - -        public String getLocale() { -            return mLocales; -        } -    } - -    private static native long nativeNew(int fd); - -    private static native long nativeNewFromPath(String path); - -    private static native long nativeNewFromAssetFileDescriptor( -            AssetFileDescriptor afd, long offset, long size); - -    private static native int[] nativeSuggestSelection( -            long context, -            String text, -            int selectionBegin, -            int selectionEnd, -            SelectionOptions options); - -    private static native ClassificationResult[] nativeClassifyText( -            long context, -            String text, -            int selectionBegin, -            int selectionEnd, -            ClassificationOptions options); - -    private static native AnnotatedSpan[] nativeAnnotate( -            long context, String text, AnnotationOptions options); - -    private static native void nativeClose(long context); - -    private static native String nativeGetLocales(int fd); - -    private static native int nativeGetVersion(int fd); -} diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index ae6a2fd787d7..23d12374453f 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -25,6 +25,13 @@ import android.net.WebAddress;   * Cookies are manipulated according to RFC2109.   */  public abstract class CookieManager { +    /** +     * @deprecated This class should not be constructed by applications, use {@link #getInstance} +     * instead to fetch the singleton instance. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public CookieManager() {}      @Override      protected Object clone() throws CloneNotSupportedException { diff --git a/core/java/android/webkit/RenderProcessGoneDetail.java b/core/java/android/webkit/RenderProcessGoneDetail.java index 0843e26ea19c..9beeaa5c1524 100644 --- a/core/java/android/webkit/RenderProcessGoneDetail.java +++ b/core/java/android/webkit/RenderProcessGoneDetail.java @@ -22,6 +22,13 @@ package android.webkit;   **/  public abstract class RenderProcessGoneDetail {      /** +     * @deprecated This class should not be constructed by applications. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public RenderProcessGoneDetail() {} + +    /**       * Indicates whether the render process was observed to crash, or whether       * it was killed by the system.       * diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java index 7839a00eff69..ca33a0c659af 100644 --- a/core/java/android/webkit/SafeBrowsingResponse.java +++ b/core/java/android/webkit/SafeBrowsingResponse.java @@ -27,6 +27,12 @@ package android.webkit;   * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.   */  public abstract class SafeBrowsingResponse { +    /** +     * @deprecated This class should not be constructed by applications. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public SafeBrowsingResponse() {}      /**       * Display the default interstitial. diff --git a/core/java/android/webkit/ServiceWorkerController.java b/core/java/android/webkit/ServiceWorkerController.java index 3517c74b680e..d7e0715a3770 100644 --- a/core/java/android/webkit/ServiceWorkerController.java +++ b/core/java/android/webkit/ServiceWorkerController.java @@ -38,6 +38,14 @@ import android.annotation.Nullable;  public abstract class ServiceWorkerController {      /** +     * @deprecated This class should not be constructed by applications, use {@link #getInstance()} +     * instead to fetch the singleton instance. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public ServiceWorkerController() {} + +    /**       * Returns the default ServiceWorkerController instance. At present there is       * only one ServiceWorkerController instance for all WebView instances,       * however this restriction may be relaxed in the future. diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java index 30f465cb42c6..99081827658a 100644 --- a/core/java/android/webkit/TracingController.java +++ b/core/java/android/webkit/TracingController.java @@ -43,6 +43,13 @@ import java.util.concurrent.Executor;   * </pre></p>   */  public abstract class TracingController { +    /** +     * @deprecated This class should not be constructed by applications, use {@link #getInstance} +     * instead to fetch the singleton instance. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public TracingController() {}      /**       * Returns the default TracingController instance. At present there is diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java index f6166c58a4c9..f346c602c3b6 100644 --- a/core/java/android/webkit/WebViewDatabase.java +++ b/core/java/android/webkit/WebViewDatabase.java @@ -31,6 +31,14 @@ import android.content.Context;   */  public abstract class WebViewDatabase {      /** +     * @deprecated This class should not be constructed by applications, use {@link +     * #getInstance(Context)} instead to fetch the singleton instance. +     */ +    // TODO(ntfschr): mark this as @SystemApi after a year. +    @Deprecated +    public WebViewDatabase() {} + +    /**       * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}       */      protected static final String LOGTAG = "webviewdatabase"; diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 0fef9a54a2ff..12cc54d7241e 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -1338,7 +1338,9 @@ public class ImageView extends View {              return;          }          if (matrix == null) { -            mDrawable.setBounds(0, 0, getWidth(), getHeight()); +            final int vwidth = getWidth() - mPaddingLeft - mPaddingRight; +            final int vheight = getHeight() - mPaddingTop - mPaddingBottom; +            mDrawable.setBounds(0, 0, vwidth, vheight);          } else {              mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);              if (mDrawMatrix == null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index bbfac440d414..f95b3ce98264 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -321,6 +321,12 @@ import java.util.function.Supplier;   * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize   * @attr ref android.R.styleable#TextView_autoSizeStepGranularity   * @attr ref android.R.styleable#TextView_autoSizePresetSizes + * @attr ref android.R.styleable#TextView_textCursorDrawable + * @attr ref android.R.styleable#TextView_textSelectHandle + * @attr ref android.R.styleable#TextView_textSelectHandleLeft + * @attr ref android.R.styleable#TextView_textSelectHandleRight + * @attr ref android.R.styleable#TextView_allowUndo + * @attr ref android.R.styleable#TextView_enabled   */  @RemoteView  public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl index 44867c7719cd..0c203ab76346 100644 --- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl +++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl @@ -24,4 +24,14 @@ interface IProcessStats {      byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);      ParcelFileDescriptor getStatsOverTime(long minTime);      int getCurrentMemoryState(); + +    /** +     * Get stats committed after highWaterMarkMs +     * @param highWaterMarkMs Report stats committed after this time. +     * @param section Integer mask to indicate which sections to include in the stats. +     * @param doAggregate Whether to aggregate the stats or keep them separated. +     * @param List of Files of individual commits in protobuf binary or one that is merged from them. +     */ +     long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate, +        out List<ParcelFileDescriptor> committedStats);  } diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index f6e99ba90b86..e7ac5664c3ee 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -158,6 +158,25 @@ public final class ProcessStats implements Parcelable {              STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY      }; +    // Should report process stats. +    public static final int REPORT_PROC_STATS = 0x01; +    // Should report package process stats. +    public static final int REPORT_PKG_PROC_STATS = 0x02; +    // Should report package service stats. +    public static final int REPORT_PKG_SVC_STATS = 0x04; +    // Should report package association stats. +    public static final int REPORT_PKG_ASC_STATS = 0x08; +    // Should report package stats. +    public static final int REPORT_PKG_STATS = 0x0E; +    // Should report all stats. +    public static final int REPORT_ALL = 0x0F; + +    public static final int[] OPTIONS = +            {REPORT_PROC_STATS, REPORT_PKG_PROC_STATS, REPORT_PKG_SVC_STATS, REPORT_PKG_ASC_STATS, +                    REPORT_PKG_STATS, REPORT_ALL}; +    public static final String[] OPTIONS_STR = +            {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"}; +      // Current version of the parcel format.      private static final int PARCEL_VERSION = 34;      // In-memory Parcel magic number, used to detect attempts to unmarshall bad data @@ -1412,7 +1431,7 @@ public final class ProcessStats implements Parcelable {      }      public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary, -            boolean dumpDetails, boolean dumpAll, boolean activeOnly) { +            boolean dumpDetails, boolean dumpAll, boolean activeOnly, int section) {          long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,                  mStartTime, now);          boolean sepNeeded = false; @@ -1421,176 +1440,205 @@ public final class ProcessStats implements Parcelable {              mSysMemUsage.dump(pw, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);              sepNeeded = true;          } -        ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();          boolean printedHeader = false; -        for (int ip=0; ip<pkgMap.size(); ip++) { -            final String pkgName = pkgMap.keyAt(ip); -            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); -            for (int iu=0; iu<uids.size(); iu++) { -                final int uid = uids.keyAt(iu); -                final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); -                for (int iv=0; iv<vpkgs.size(); iv++) { -                    final long vers = vpkgs.keyAt(iv); -                    final PackageState pkgState = vpkgs.valueAt(iv); -                    final int NPROCS = pkgState.mProcesses.size(); -                    final int NSRVS = pkgState.mServices.size(); -                    final int NASCS = pkgState.mAssociations.size(); -                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); -                    if (!pkgMatch) { -                        boolean procMatch = false; -                        for (int iproc=0; iproc<NPROCS; iproc++) { -                            ProcessState proc = pkgState.mProcesses.valueAt(iproc); -                            if (reqPackage.equals(proc.getName())) { -                                procMatch = true; -                                break; -                            } -                        } -                        if (!procMatch) { -                            continue; -                        } -                    } -                    if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { -                        if (!printedHeader) { -                            if (sepNeeded) pw.println(); -                            pw.println("Per-Package Stats:"); -                            printedHeader = true; -                            sepNeeded = true; -                        } -                        pw.print("  * "); pw.print(pkgName); pw.print(" / "); -                                UserHandle.formatUid(pw, uid); pw.print(" / v"); -                                pw.print(vers); pw.println(":"); -                    } -                    if (!dumpSummary || dumpAll) { -                        for (int iproc=0; iproc<NPROCS; iproc++) { -                            ProcessState proc = pkgState.mProcesses.valueAt(iproc); -                            if (!pkgMatch && !reqPackage.equals(proc.getName())) { -                                continue; +        if ((section & REPORT_PKG_STATS) != 0) { +            ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = +                    mPackages.getMap(); +            for (int ip = 0; ip < pkgMap.size(); ip++) { +                final String pkgName = pkgMap.keyAt(ip); +                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    final int uid = uids.keyAt(iu); +                    final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); +                    for (int iv = 0; iv < vpkgs.size(); iv++) { +                        final long vers = vpkgs.keyAt(iv); +                        final PackageState pkgState = vpkgs.valueAt(iv); +                        final int NPROCS = pkgState.mProcesses.size(); +                        final int NSRVS = pkgState.mServices.size(); +                        final int NASCS = pkgState.mAssociations.size(); +                        final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); +                        if (!pkgMatch) { +                            boolean procMatch = false; +                            for (int iproc = 0; iproc < NPROCS; iproc++) { +                                ProcessState proc = pkgState.mProcesses.valueAt(iproc); +                                if (reqPackage.equals(proc.getName())) { +                                    procMatch = true; +                                    break; +                                }                              } -                            if (activeOnly && !proc.isInUse()) { -                                pw.print("      (Not active: "); -                                        pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")"); +                            if (!procMatch) {                                  continue;                              } -                            pw.print("      Process "); -                            pw.print(pkgState.mProcesses.keyAt(iproc)); -                            if (proc.getCommonProcess().isMultiPackage()) { -                                pw.print(" (multi, "); -                            } else { -                                pw.print(" (unique, "); +                        } +                        if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { +                            if (!printedHeader) { +                                if (sepNeeded) pw.println(); +                                pw.println("Per-Package Stats:"); +                                printedHeader = true; +                                sepNeeded = true;                              } -                            pw.print(proc.getDurationsBucketCount()); -                            pw.print(" entries)"); +                            pw.print("  * "); +                            pw.print(pkgName); +                            pw.print(" / "); +                            UserHandle.formatUid(pw, uid); +                            pw.print(" / v"); +                            pw.print(vers);                              pw.println(":"); -                            proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, -                                    ALL_PROC_STATES, now); -                            proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, -                                    ALL_PROC_STATES, now); -                            proc.dumpInternalLocked(pw, "        ", dumpAll);                          } -                    } else { -                        ArrayList<ProcessState> procs = new ArrayList<ProcessState>(); -                        for (int iproc=0; iproc<NPROCS; iproc++) { -                            ProcessState proc = pkgState.mProcesses.valueAt(iproc); -                            if (!pkgMatch && !reqPackage.equals(proc.getName())) { -                                continue; -                            } -                            if (activeOnly && !proc.isInUse()) { -                                continue; +                        if ((section & REPORT_PKG_PROC_STATS) != 0) { +                            if (!dumpSummary || dumpAll) { +                                for (int iproc = 0; iproc < NPROCS; iproc++) { +                                    ProcessState proc = pkgState.mProcesses.valueAt(iproc); +                                    if (!pkgMatch && !reqPackage.equals(proc.getName())) { +                                        continue; +                                    } +                                    if (activeOnly && !proc.isInUse()) { +                                        pw.print("      (Not active: "); +                                        pw.print(pkgState.mProcesses.keyAt(iproc)); +                                        pw.println(")"); +                                        continue; +                                    } +                                    pw.print("      Process "); +                                    pw.print(pkgState.mProcesses.keyAt(iproc)); +                                    if (proc.getCommonProcess().isMultiPackage()) { +                                        pw.print(" (multi, "); +                                    } else { +                                        pw.print(" (unique, "); +                                    } +                                    pw.print(proc.getDurationsBucketCount()); +                                    pw.print(" entries)"); +                                    pw.println(":"); +                                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, +                                            ALL_MEM_ADJ, +                                            ALL_PROC_STATES, now); +                                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, +                                            ALL_PROC_STATES, now); +                                    proc.dumpInternalLocked(pw, "        ", dumpAll); +                                } +                            } else { +                                ArrayList<ProcessState> procs = new ArrayList<ProcessState>(); +                                for (int iproc = 0; iproc < NPROCS; iproc++) { +                                    ProcessState proc = pkgState.mProcesses.valueAt(iproc); +                                    if (!pkgMatch && !reqPackage.equals(proc.getName())) { +                                        continue; +                                    } +                                    if (activeOnly && !proc.isInUse()) { +                                        continue; +                                    } +                                    procs.add(proc); +                                } +                                DumpUtils.dumpProcessSummaryLocked(pw, "      ", "Prc ", procs, +                                        ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES, +                                        now, totalTime);                              } -                            procs.add(proc); -                        } -                        DumpUtils.dumpProcessSummaryLocked(pw, "      ", "Prc ", procs, -                                ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES, -                                now, totalTime); -                    } -                    for (int isvc=0; isvc<NSRVS; isvc++) { -                        ServiceState svc = pkgState.mServices.valueAt(isvc); -                        if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) { -                            continue;                          } -                        if (activeOnly && !svc.isInUse()) { -                            pw.print("      (Not active service: "); -                                    pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")"); -                            continue; -                        } -                        if (dumpAll) { -                            pw.print("      Service "); -                        } else { -                            pw.print("      * Svc "); -                        } -                        pw.print(pkgState.mServices.keyAt(isvc)); -                        pw.println(":"); -                        pw.print("        Process: "); pw.println(svc.getProcessName()); -                        svc.dumpStats(pw, "        ", "          ", "    ", -                                now, totalTime, dumpSummary, dumpAll); -                    } -                    for (int iasc=0; iasc<NASCS; iasc++) { -                        AssociationState asc = pkgState.mAssociations.valueAt(iasc); -                        if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { -                            continue; -                        } -                        if (activeOnly && !asc.isInUse()) { -                            pw.print("      (Not active association: "); -                            pw.print(pkgState.mAssociations.keyAt(iasc)); pw.println(")"); -                            continue; +                        if ((section & REPORT_PKG_SVC_STATS) != 0) { +                            for (int isvc = 0; isvc < NSRVS; isvc++) { +                                ServiceState svc = pkgState.mServices.valueAt(isvc); +                                if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) { +                                    continue; +                                } +                                if (activeOnly && !svc.isInUse()) { +                                    pw.print("      (Not active service: "); +                                    pw.print(pkgState.mServices.keyAt(isvc)); +                                    pw.println(")"); +                                    continue; +                                } +                                if (dumpAll) { +                                    pw.print("      Service "); +                                } else { +                                    pw.print("      * Svc "); +                                } +                                pw.print(pkgState.mServices.keyAt(isvc)); +                                pw.println(":"); +                                pw.print("        Process: "); +                                pw.println(svc.getProcessName()); +                                svc.dumpStats(pw, "        ", "          ", "    ", +                                        now, totalTime, dumpSummary, dumpAll); +                            }                          } -                        if (dumpAll) { -                            pw.print("      Association "); -                        } else { -                            pw.print("      * Asc "); +                        if ((section & REPORT_PKG_ASC_STATS) != 0) { +                            for (int iasc = 0; iasc < NASCS; iasc++) { +                                AssociationState asc = pkgState.mAssociations.valueAt(iasc); +                                if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { +                                    continue; +                                } +                                if (activeOnly && !asc.isInUse()) { +                                    pw.print("      (Not active association: "); +                                    pw.print(pkgState.mAssociations.keyAt(iasc)); +                                    pw.println(")"); +                                    continue; +                                } +                                if (dumpAll) { +                                    pw.print("      Association "); +                                } else { +                                    pw.print("      * Asc "); +                                } +                                pw.print(pkgState.mAssociations.keyAt(iasc)); +                                pw.println(":"); +                                pw.print("        Process: "); +                                pw.println(asc.getProcessName()); +                                asc.dumpStats(pw, "        ", "          ", "    ", +                                        now, totalTime, dumpDetails, dumpAll); +                            }                          } -                        pw.print(pkgState.mAssociations.keyAt(iasc)); -                        pw.println(":"); -                        pw.print("        Process: "); pw.println(asc.getProcessName()); -                        asc.dumpStats(pw, "        ", "          ", "    ", -                                now, totalTime, dumpDetails, dumpAll);                      }                  }              }          } -        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); -        printedHeader = false; -        int numShownProcs = 0, numTotalProcs = 0; -        for (int ip=0; ip<procMap.size(); ip++) { -            String procName = procMap.keyAt(ip); -            SparseArray<ProcessState> uids = procMap.valueAt(ip); -            for (int iu=0; iu<uids.size(); iu++) { -                int uid = uids.keyAt(iu); -                numTotalProcs++; -                final ProcessState proc = uids.valueAt(iu); -                if (!proc.hasAnyData()) { -                    continue; -                } -                if (!proc.isMultiPackage()) { -                    continue; -                } -                if (reqPackage != null && !reqPackage.equals(procName) -                        && !reqPackage.equals(proc.getPackage())) { -                    continue; -                } -                numShownProcs++; -                if (sepNeeded) { -                    pw.println(); -                } -                sepNeeded = true; -                if (!printedHeader) { -                    pw.println("Multi-Package Common Processes:"); -                    printedHeader = true; -                } -                if (activeOnly && !proc.isInUse()) { -                    pw.print("      (Not active: "); pw.print(procName); pw.println(")"); -                    continue; +        if ((section & REPORT_PROC_STATS) != 0) { +            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); +            printedHeader = false; +            int numShownProcs = 0, numTotalProcs = 0; +            for (int ip = 0; ip < procMap.size(); ip++) { +                String procName = procMap.keyAt(ip); +                SparseArray<ProcessState> uids = procMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    int uid = uids.keyAt(iu); +                    numTotalProcs++; +                    final ProcessState proc = uids.valueAt(iu); +                    if (!proc.hasAnyData()) { +                        continue; +                    } +                    if (!proc.isMultiPackage()) { +                        continue; +                    } +                    if (reqPackage != null && !reqPackage.equals(procName) +                            && !reqPackage.equals(proc.getPackage())) { +                        continue; +                    } +                    numShownProcs++; +                    if (sepNeeded) { +                        pw.println(); +                    } +                    sepNeeded = true; +                    if (!printedHeader) { +                        pw.println("Multi-Package Common Processes:"); +                        printedHeader = true; +                    } +                    if (activeOnly && !proc.isInUse()) { +                        pw.print("      (Not active: "); +                        pw.print(procName); +                        pw.println(")"); +                        continue; +                    } +                    pw.print("  * "); +                    pw.print(procName); +                    pw.print(" / "); +                    UserHandle.formatUid(pw, uid); +                    pw.print(" ("); +                    pw.print(proc.getDurationsBucketCount()); +                    pw.print(" entries)"); +                    pw.println(":"); +                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, +                            ALL_PROC_STATES, now); +                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now); +                    proc.dumpInternalLocked(pw, "        ", dumpAll);                  } -                pw.print("  * "); pw.print(procName); pw.print(" / "); -                        UserHandle.formatUid(pw, uid); -                        pw.print(" ("); pw.print(proc.getDurationsBucketCount()); -                        pw.print(" entries)"); pw.println(":"); -                proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, -                        ALL_PROC_STATES, now); -                proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now); -                proc.dumpInternalLocked(pw, "        ", dumpAll);              } +            pw.print("  Total procs: "); pw.print(numShownProcs); +            pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");          }          if (dumpAll) { @@ -1598,8 +1646,7 @@ public final class ProcessStats implements Parcelable {                  pw.println();              }              sepNeeded = true; -            pw.print("  Total procs: "); pw.print(numShownProcs); -                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total"); +              if (mTrackingAssociations.size() > 0) {                  pw.println();                  pw.println("Tracking associations:"); @@ -1866,7 +1913,10 @@ public final class ProcessStats implements Parcelable {          return outProcs;      } -    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) { +    /** +     * Prints checkin style stats dump. +     */ +    public void dumpCheckinLocked(PrintWriter pw, String reqPackage, int section) {          final long now = SystemClock.uptimeMillis();          final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =                  mPackages.getMap(); @@ -1895,50 +1945,61 @@ public final class ProcessStats implements Parcelable {          }          pw.println();          pw.print("config,"); pw.println(mRuntime); -        for (int ip=0; ip<pkgMap.size(); ip++) { -            final String pkgName = pkgMap.keyAt(ip); -            if (reqPackage != null && !reqPackage.equals(pkgName)) { -                continue; -            } -            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); -            for (int iu=0; iu<uids.size(); iu++) { -                final int uid = uids.keyAt(iu); -                final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); -                for (int iv=0; iv<vpkgs.size(); iv++) { -                    final long vers = vpkgs.keyAt(iv); -                    final PackageState pkgState = vpkgs.valueAt(iv); -                    final int NPROCS = pkgState.mProcesses.size(); -                    final int NSRVS = pkgState.mServices.size(); -                    final int NASCS = pkgState.mAssociations.size(); -                    for (int iproc=0; iproc<NPROCS; iproc++) { -                        ProcessState proc = pkgState.mProcesses.valueAt(iproc); -                        proc.dumpPackageProcCheckin(pw, pkgName, uid, vers, -                                pkgState.mProcesses.keyAt(iproc), now); -                    } -                    for (int isvc=0; isvc<NSRVS; isvc++) { -                        final String serviceName = DumpUtils.collapseString(pkgName, -                                pkgState.mServices.keyAt(isvc)); -                        final ServiceState svc = pkgState.mServices.valueAt(isvc); -                        svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now); -                    } -                    for (int iasc=0; iasc<NASCS; iasc++) { -                        final String associationName = DumpUtils.collapseString(pkgName, -                                pkgState.mAssociations.keyAt(iasc)); -                        final AssociationState asc = pkgState.mAssociations.valueAt(iasc); -                        asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now); + +        if ((section & REPORT_PKG_STATS) != 0) { +            for (int ip = 0; ip < pkgMap.size(); ip++) { +                final String pkgName = pkgMap.keyAt(ip); +                if (reqPackage != null && !reqPackage.equals(pkgName)) { +                    continue; +                } +                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    final int uid = uids.keyAt(iu); +                    final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); +                    for (int iv = 0; iv < vpkgs.size(); iv++) { +                        final long vers = vpkgs.keyAt(iv); +                        final PackageState pkgState = vpkgs.valueAt(iv); +                        final int NPROCS = pkgState.mProcesses.size(); +                        final int NSRVS = pkgState.mServices.size(); +                        final int NASCS = pkgState.mAssociations.size(); +                        if ((section & REPORT_PKG_PROC_STATS) != 0) { +                            for (int iproc = 0; iproc < NPROCS; iproc++) { +                                ProcessState proc = pkgState.mProcesses.valueAt(iproc); +                                proc.dumpPackageProcCheckin(pw, pkgName, uid, vers, +                                        pkgState.mProcesses.keyAt(iproc), now); +                            } +                        } +                        if ((section & REPORT_PKG_SVC_STATS) != 0) { +                            for (int isvc = 0; isvc < NSRVS; isvc++) { +                                final String serviceName = DumpUtils.collapseString(pkgName, +                                        pkgState.mServices.keyAt(isvc)); +                                final ServiceState svc = pkgState.mServices.valueAt(isvc); +                                svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now); +                            } +                        } +                        if ((section & REPORT_PKG_ASC_STATS) != 0) { +                            for (int iasc = 0; iasc < NASCS; iasc++) { +                                final String associationName = DumpUtils.collapseString(pkgName, +                                        pkgState.mAssociations.keyAt(iasc)); +                                final AssociationState asc = pkgState.mAssociations.valueAt(iasc); +                                asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now); +                            } +                        }                      }                  }              }          } -        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); -        for (int ip=0; ip<procMap.size(); ip++) { -            String procName = procMap.keyAt(ip); -            SparseArray<ProcessState> uids = procMap.valueAt(ip); -            for (int iu=0; iu<uids.size(); iu++) { -                final int uid = uids.keyAt(iu); -                final ProcessState procState = uids.valueAt(iu); -                procState.dumpProcCheckin(pw, procName, uid, now); +        if ((section & REPORT_PROC_STATS) != 0) { +            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); +            for (int ip = 0; ip < procMap.size(); ip++) { +                String procName = procMap.keyAt(ip); +                SparseArray<ProcessState> uids = procMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    final int uid = uids.keyAt(iu); +                    final ProcessState procState = uids.valueAt(iu); +                    procState.dumpProcCheckin(pw, procName, uid, now); +                }              }          }          pw.print("total"); @@ -2013,9 +2074,10 @@ public final class ProcessStats implements Parcelable {          }      } -    public void writeToProto(ProtoOutputStream proto, long fieldId, long now) { -        final long token = proto.start(fieldId); - +    /** +     * Writes to ProtoOutputStream. +     */ +    public void writeToProto(ProtoOutputStream proto, long now, int section) {          proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);          proto.write(ProcessStatsSectionProto.END_REALTIME_MS,                  mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime); @@ -2024,15 +2086,15 @@ public final class ProcessStats implements Parcelable {          proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);          proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);          boolean partial = true; -        if ((mFlags&FLAG_SHUTDOWN) != 0) { +        if ((mFlags & FLAG_SHUTDOWN) != 0) {              proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);              partial = false;          } -        if ((mFlags&FLAG_SYSPROPS) != 0) { +        if ((mFlags & FLAG_SYSPROPS) != 0) {              proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);              partial = false;          } -        if ((mFlags&FLAG_COMPLETE) != 0) { +        if ((mFlags & FLAG_COMPLETE) != 0) {              proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);              partial = false;          } @@ -2041,31 +2103,34 @@ public final class ProcessStats implements Parcelable {          }          final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); -        for (int ip=0; ip<procMap.size(); ip++) { -            final String procName = procMap.keyAt(ip); -            final SparseArray<ProcessState> uids = procMap.valueAt(ip); -            for (int iu=0; iu<uids.size(); iu++) { -                final int uid = uids.keyAt(iu); -                final ProcessState procState = uids.valueAt(iu); -                procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName, -                        uid, now); +        if ((section & REPORT_PROC_STATS) != 0) { +            for (int ip = 0; ip < procMap.size(); ip++) { +                final String procName = procMap.keyAt(ip); +                final SparseArray<ProcessState> uids = procMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    final int uid = uids.keyAt(iu); +                    final ProcessState procState = uids.valueAt(iu); +                    procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName, +                            uid, now); +                }              }          } -        final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = -                mPackages.getMap(); -        for (int ip = 0; ip < pkgMap.size(); ip++) { -            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); -            for (int iu = 0; iu < uids.size(); iu++) { -                final LongSparseArray<PackageState> vers = uids.valueAt(iu); -                for (int iv = 0; iv < vers.size(); iv++) { -                    final PackageState pkgState = vers.valueAt(iv); -                    pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now); +        if ((section & REPORT_PKG_STATS) != 0) { +            final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = +                    mPackages.getMap(); +            for (int ip = 0; ip < pkgMap.size(); ip++) { +                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); +                for (int iu = 0; iu < uids.size(); iu++) { +                    final LongSparseArray<PackageState> vers = uids.valueAt(iu); +                    for (int iv = 0; iv < vers.size(); iv++) { +                        final PackageState pkgState = vers.valueAt(iv); +                        pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now, +                                section); +                    }                  }              }          } - -        proto.end(token);      }      final public static class ProcessStateHolder { @@ -2110,30 +2175,39 @@ public final class ProcessStats implements Parcelable {              return as;          } -        public void writeToProto(ProtoOutputStream proto, long fieldId, long now) { +        /** +         * Writes the containing stats into proto, with options to choose smaller sections. +         */ +        public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) {              final long token = proto.start(fieldId);              proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName);              proto.write(ProcessStatsPackageProto.UID, mUid);              proto.write(ProcessStatsPackageProto.VERSION, mVersionCode); -            for (int ip = 0; ip < mProcesses.size(); ip++) { -                final String procName = mProcesses.keyAt(ip); -                final ProcessState procState = mProcesses.valueAt(ip); -                procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName, -                        mUid, now); +            if ((section & ProcessStats.REPORT_PKG_PROC_STATS) != 0) { +                for (int ip = 0; ip < mProcesses.size(); ip++) { +                    final String procName = mProcesses.keyAt(ip); +                    final ProcessState procState = mProcesses.valueAt(ip); +                    procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName, +                            mUid, now); +                }              } -            for (int is = 0; is < mServices.size(); is++) { -                final ServiceState serviceState = mServices.valueAt(is); -                serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS, -                        now); +            if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) { +                for (int is = 0; is < mServices.size(); is++) { +                    final ServiceState serviceState = mServices.valueAt(is); +                    serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS, +                            now); +                }              } -            for (int ia=0; ia<mAssociations.size(); ia++) { -                final AssociationState ascState = mAssociations.valueAt(ia); -                ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS, -                        now); +            if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) { +                for (int ia = 0; ia < mAssociations.size(); ia++) { +                    final AssociationState ascState = mAssociations.valueAt(ia); +                    ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS, +                            now); +                }              }              proto.end(token); diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index cb282b69845c..0080ace230a2 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -66,13 +66,13 @@ public class AmbientDisplayConfiguration {          return !TextUtils.isEmpty(doubleTapSensorType());      } -    public boolean reachGestureEnabled(int user) { -        return boolSettingDefaultOn(Settings.Secure.DOZE_REACH_GESTURE, user) -                && reachGestureAvailable(); +    public boolean wakeLockScreenGestureEnabled(int user) { +        return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user) +                && wakeLockScreenGestureAvailable();      } -    public boolean reachGestureAvailable() { -        return !TextUtils.isEmpty(reachSensorType()); +    public boolean wakeLockScreenGestureAvailable() { +        return !TextUtils.isEmpty(wakeLockScreenSensorType());      }      public boolean wakeScreenGestureEnabled(int user) { @@ -92,8 +92,8 @@ public class AmbientDisplayConfiguration {          return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);      } -    public String reachSensorType() { -        return mContext.getResources().getString(R.string.config_dozeReachSensorType); +    public String wakeLockScreenSensorType() { +        return mContext.getResources().getString(R.string.config_dozeWakeLockScreenSensorType);      }      public String wakeScreenSensorType() { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 31f13c33c167..33b9ff7cee4f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -337,6 +337,9 @@ public class BatteryStatsImpl extends BatteryStats {      private final PlatformIdleStateCallback mPlatformIdleStateCallback; +    /** +     * This handler is running on {@link BackgroundThread}. +     */      final class MyHandler extends Handler {          public MyHandler(Looper looper) {              super(looper, null, true); diff --git a/core/java/com/android/internal/os/StoragedUidIoStatsReader.java b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java new file mode 100644 index 000000000000..9b0346923cd3 --- /dev/null +++ b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.os.StrictMode; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + + +/** + * Reads /proc/uid_io/stats which has the line format: + * + * uid: foreground_read_chars foreground_write_chars foreground_read_bytes foreground_write_bytes + * background_read_chars background_write_chars background_read_bytes background_write_bytes + * foreground_fsync background_fsync + * + * This provides the number of bytes/chars read/written in foreground/background for each uid. + * The file contains a monotonically increasing count of bytes/chars for a single boot. + */ +public class StoragedUidIoStatsReader { + +    private static final String TAG = StoragedUidIoStatsReader.class.getSimpleName(); +    private static String sUidIoFile = "/proc/uid_io/stats"; + +    public StoragedUidIoStatsReader() { +    } + +    @VisibleForTesting +    public StoragedUidIoStatsReader(String file) { +        sUidIoFile = file; +    } + +    /** +     * Notifies when new data is available. +     */ +    public interface Callback { + +        /** +         * Provides data to the client. +         * +         * Note: Bytes are I/O events from a storage device. Chars are data requested by syscalls, +         *   and can be satisfied by caching. +         */ +        void onUidStorageStats(int uid, long fgCharsRead, long fgCharsWrite, long fgBytesRead, +                long fgBytesWrite, long bgCharsRead, long bgCharsWrite, long bgBytesRead, +                long bgBytesWrite, long fgFsync, long bgFsync); +    } + +    /** +     * Reads the proc file, calling into the callback with raw absolute value of I/O stats +     * for each UID. +     * +     * @param callback The callback to invoke for each line of the proc file. +     */ +    public void readAbsolute(Callback callback) { +        final int oldMask = StrictMode.allowThreadDiskReadsMask(); +        File file = new File(sUidIoFile); +        try (BufferedReader reader = Files.newBufferedReader(file.toPath())) { +            String line; +            while ((line = reader.readLine()) != null) { +                String[] fields = TextUtils.split(line, " "); +                if (fields.length != 11) { +                    Slog.e(TAG, "Malformed entry in " + sUidIoFile + ": " + line); +                    continue; +                } +                try { +                    final String uidStr = fields[0]; +                    final int uid = Integer.parseInt(fields[0], 10); +                    final long fgCharsRead = Long.parseLong(fields[1], 10); +                    final long fgCharsWrite = Long.parseLong(fields[2], 10); +                    final long fgBytesRead = Long.parseLong(fields[3], 10); +                    final long fgBytesWrite = Long.parseLong(fields[4], 10); +                    final long bgCharsRead = Long.parseLong(fields[5], 10); +                    final long bgCharsWrite = Long.parseLong(fields[6], 10); +                    final long bgBytesRead = Long.parseLong(fields[7], 10); +                    final long bgBytesWrite = Long.parseLong(fields[8], 10); +                    final long fgFsync = Long.parseLong(fields[9], 10); +                    final long bgFsync = Long.parseLong(fields[10], 10); +                    callback.onUidStorageStats(uid, fgCharsRead, fgCharsWrite, fgBytesRead, +                            fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite, +                            fgFsync, bgFsync); +                } catch (NumberFormatException e) { +                    Slog.e(TAG, "Could not parse entry in " + sUidIoFile + ": " + e.getMessage()); +                } +            } +        } catch (IOException e) { +            Slog.e(TAG, "Failed to read " + sUidIoFile + ": " + e.getMessage()); +        } finally { +            StrictMode.setThreadPolicyMask(oldMask); +        } +    } +} diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 927322e97e28..98b7b5d28779 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -133,15 +133,16 @@ public final class Zygote {       * if this is the parent, or -1 on error.       */      public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, -          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, -          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, -          String packageName) { +            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, +            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, +            String packageName, String[] packagesForUid, String[] visibleVolIds) {          VM_HOOKS.preFork();          // Resets nice priority for zygote process.          resetNicePriority();          int pid = nativeForkAndSpecialize(                    uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, -                  fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName); +                  fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName, +                  packagesForUid, visibleVolIds);          // Enable tracing as soon as possible for the child process.          if (pid == 0) {              Trace.setTracingEnabled(true, runtimeFlags); @@ -154,9 +155,9 @@ public final class Zygote {      }      native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags, -          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, -          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, -          String packageName); +            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, +            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, +            String packageName, String[] packagesForUid, String[] visibleVolIds);      /**       * Called to do any initialization before starting an application. diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 06c41d858f7c..4a94ec4a4071 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -241,7 +241,8 @@ class ZygoteConnection {          pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,                  parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,                  parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, -                parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName); +                parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName, +                parsedArgs.packagesForUid, parsedArgs.visibleVolIds);          try {              if (pid == 0) { @@ -432,6 +433,12 @@ class ZygoteConnection {          /** from --package-name */          String packageName; +        /** from --packages-for-uid */ +        String[] packagesForUid; + +        /** from --visible-vols */ +        String[] visibleVolIds; +          /**           * Any args after and including the first non-option arg           * (or after a '--') @@ -687,6 +694,10 @@ class ZygoteConnection {                          throw new IllegalArgumentException("Duplicate arg specified");                      }                      packageName = arg.substring(arg.indexOf('=') + 1); +                } else if (arg.startsWith("--packages-for-uid=")) { +                    packagesForUid = arg.substring(arg.indexOf('=') + 1).split(","); +                } else if (arg.startsWith("--visible-vols=")) { +                    visibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");                  } else {                      break;                  } diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index b16359727e40..a45b4933a900 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -622,13 +622,17 @@ void util_multiplyMV(JNIEnv *env, jclass clazz,  // --------------------------------------------------------------------------- +// The internal format is no longer the same as pixel format, per Table 2 in +// https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml  static int checkInternalFormat(SkColorType colorType, int internalformat,      int type)  {      switch(colorType) {          case kN32_SkColorType:              return (type == GL_UNSIGNED_BYTE && -                internalformat == GL_RGBA) ? 0 : -1; +                    internalformat == GL_RGBA) || +                (type == GL_UNSIGNED_BYTE && +                 internalformat == GL_SRGB8_ALPHA8) ? 0 : -1;          case kAlpha_8_SkColorType:              return (type == GL_UNSIGNED_BYTE &&                  internalformat == GL_ALPHA) ? 0 : -1; diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index eba4c50b0855..343aef291720 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -674,7 +674,7 @@ int register_android_graphics_Canvas(JNIEnv* env) {      int ret = 0;      ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));      ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods)); -    ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods)); +    ret |= RegisterMethodsOrDie(env, "android/graphics/BaseRecordingCanvas", gDrawMethods, NELEM(gDrawMethods));      return ret;  } diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index 6df23f72bdd3..a1f2377041e8 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -58,6 +58,11 @@ socket_connect_local(JNIEnv *env, jobject object,      int ret;      int fd; +    if (name == NULL) { +        jniThrowNullPointerException(env, NULL); +        return; +    } +      fd = jniGetFDFromFileDescriptor(env, fileDescriptor);      if (env->ExceptionCheck()) { diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index dfa5de6b65c6..b70485d9a0ea 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -28,6 +28,14 @@ void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {      android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());  } +void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn) { +    ScopedUtfChars pathChars(env, path); +    ScopedUtfChars appNameChars(env, appName); +    ScopedUtfChars appPrefChars(env, appPref); +    android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(), +            appPrefChars.c_str(), devOptIn); +} +  void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {      android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader(          env, classLoader); @@ -44,6 +52,7 @@ void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) {  const JNINativeMethod g_methods[] = {      { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) }, +    { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },      { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },      { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },  }; diff --git a/core/jni/android_text_LineBreaker.cpp b/core/jni/android_text_LineBreaker.cpp index dac108ef5497..543910727ffd 100644 --- a/core/jni/android_text_LineBreaker.cpp +++ b/core/jni/android_text_LineBreaker.cpp @@ -41,17 +41,6 @@  namespace android { -struct JLineBreaksID { -    jfieldID breaks; -    jfieldID widths; -    jfieldID ascents; -    jfieldID descents; -    jfieldID flags; -}; - -static jclass gLineBreaks_class; -static JLineBreaksID gLineBreaks_fieldID; -  static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray javaArray) {      if (javaArray == nullptr) {           return std::vector<float>(); @@ -85,34 +74,7 @@ static jlong nGetReleaseFunc() {      return reinterpret_cast<jlong>(nFinish);  } -static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, -                        jfloatArray recycleWidths, jfloatArray recycleAscents, -                        jfloatArray recycleDescents, jintArray recycleFlags, -                        jint recycleLength, const minikin::LineBreakResult& result) { -    const size_t nBreaks = result.breakPoints.size(); -    if ((size_t)recycleLength < nBreaks) { -        // have to reallocate buffers -        recycleBreaks = env->NewIntArray(nBreaks); -        recycleWidths = env->NewFloatArray(nBreaks); -        recycleAscents = env->NewFloatArray(nBreaks); -        recycleDescents = env->NewFloatArray(nBreaks); -        recycleFlags = env->NewIntArray(nBreaks); - -        env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks); -        env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths); -        env->SetObjectField(recycle, gLineBreaks_fieldID.ascents, recycleAscents); -        env->SetObjectField(recycle, gLineBreaks_fieldID.descents, recycleDescents); -        env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags); -    } -    // copy data -    env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data()); -    env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data()); -    env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data()); -    env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data()); -    env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data()); -} - -static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, +static jlong nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,          // Inputs          jcharArray javaText,          jlong measuredTextPtr, @@ -122,18 +84,7 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,          jfloat restWidth,          jintArray variableTabStops,          jint defaultTabStop, -        jint indentsOffset, - -        // Outputs -        jobject recycle, -        jint recycleLength, -        jintArray recycleBreaks, -        jfloatArray recycleWidths, -        jfloatArray recycleAscents, -        jfloatArray recycleDescents, -        jintArray recycleFlags, -        jfloatArray charWidths) { - +        jint indentsOffset) {      minikin::android::StaticLayoutNative* builder = toNative(nativePtr);      ScopedCharArrayRO text(env, javaText); @@ -141,14 +92,44 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,      minikin::U16StringPiece u16Text(text.get(), length);      minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr); -    minikin::LineBreakResult result = builder->computeBreaks( -            u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset, -            tabStops.get(), tabStops.size(), defaultTabStop); -    recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents, -            recycleFlags, recycleLength, result); +    std::unique_ptr<minikin::LineBreakResult> result = +          std::make_unique<minikin::LineBreakResult>(builder->computeBreaks( +                u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset, +                tabStops.get(), tabStops.size(), defaultTabStop)); +    return reinterpret_cast<jlong>(result.release()); +} + +static jint nGetLineCount(jlong ptr) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints.size(); +} + +static jint nGetLineBreakOffset(jlong ptr, jint i) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints[i]; +} + +static jfloat nGetLineWidth(jlong ptr, jint i) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->widths[i]; +} -    return static_cast<jint>(result.breakPoints.size()); +static jfloat nGetLineAscent(jlong ptr, jint i) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->ascents[i]; +} + +static jfloat nGetLineDescent(jlong ptr, jint i) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->descents[i]; +} + +static jint nGetLineFlag(jlong ptr, jint i) { +    return reinterpret_cast<minikin::LineBreakResult*>(ptr)->flags[i]; +} + +static void nReleaseResult(jlong ptr) { +    delete reinterpret_cast<minikin::LineBreakResult*>(ptr); +} + +static jlong nGetReleaseResultFunc() { +    return reinterpret_cast<jlong>(nReleaseResult);  }  static const JNINativeMethod gMethods[] = { @@ -166,8 +147,6 @@ static const JNINativeMethod gMethods[] = {      // Regular JNI      {"nComputeLineBreaks", "("          "J"  // nativePtr - -        // Inputs          "[C"  // text          "J"  // MeasuredParagraph ptr.          "I"  // length @@ -177,31 +156,20 @@ static const JNINativeMethod gMethods[] = {          "[I"  // variableTabStops          "I"  // defaultTabStop          "I"  // indentsOffset - -        // Outputs -        "Landroid/text/NativeLineBreaker$LineBreaks;"  // recycle -        "I"  // recycleLength -        "[I"  // recycleBreaks -        "[F"  // recycleWidths -        "[F"  // recycleAscents -        "[F"  // recycleDescents -        "[I"  // recycleFlags -        ")I", (void*) nComputeLineBreaks} +        ")J", (void*) nComputeLineBreaks}, + +    // Result accessors, CriticalNatives +    {"nGetLineCount", "(J)I", (void*)nGetLineCount}, +    {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset}, +    {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth}, +    {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent}, +    {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent}, +    {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag}, +    {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},  }; -int register_android_text_LineBreaker(JNIEnv* env) -{ -    gLineBreaks_class = MakeGlobalRefOrDie(env, -            FindClassOrDie(env, "android/text/NativeLineBreaker$LineBreaks")); - -    gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I"); -    gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F"); -    gLineBreaks_fieldID.ascents = GetFieldIDOrDie(env, gLineBreaks_class, "ascents", "[F"); -    gLineBreaks_fieldID.descents = GetFieldIDOrDie(env, gLineBreaks_class, "descents", "[F"); -    gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[I"); - -    return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", -                                gMethods, NELEM(gMethods)); +int register_android_text_LineBreaker(JNIEnv* env) { +    return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", gMethods, NELEM(gMethods));  }  } diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 0701f3e0d2ed..63b004681df9 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -473,8 +473,8 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,  // SurfaceView position callback  // ---------------------------------------------------------------------------- -jmethodID gSurfaceViewPositionUpdateMethod; -jmethodID gSurfaceViewPositionLostMethod; +jmethodID gPositionListener_PositionChangedMethod; +jmethodID gPositionListener_PositionLostMethod;  static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,          jlong renderNodePtr, jobject surfaceview) { @@ -531,7 +531,7 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                  return;              } -            env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, +            env->CallVoidMethod(localref, gPositionListener_PositionLostMethod,                      info ? info->canvasContext.getFrameNumber() : 0);              env->DeleteLocalRef(localref);          } @@ -555,7 +555,7 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                  env->DeleteWeakGlobalRef(mWeakRef);                  mWeakRef = nullptr;              } else { -                env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod, +                env->CallVoidMethod(localref, gPositionListener_PositionChangedMethod,                          frameNumber, left, top, right, bottom);                  env->DeleteLocalRef(localref);              } @@ -588,7 +588,7 @@ static const JNINativeMethod gMethods[] = {      { "nGetDebugSize",         "(J)I",    (void*) android_view_RenderNode_getDebugSize },      { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },      { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators }, -    { "nRequestPositionUpdates",   "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates }, +    { "nRequestPositionUpdates",   "(JLandroid/view/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },      { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList }, @@ -677,11 +677,11 @@ static const JNINativeMethod gMethods[] = {  };  int register_android_view_RenderNode(JNIEnv* env) { -    jclass clazz = FindClassOrDie(env, "android/view/SurfaceView"); -    gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz, -            "updateSurfacePosition_renderWorker", "(JIIII)V"); -    gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz, -            "surfacePositionLost_uiRtSync", "(J)V"); +    jclass clazz = FindClassOrDie(env, "android/view/RenderNode$PositionUpdateListener"); +    gPositionListener_PositionChangedMethod = GetMethodIDOrDie(env, clazz, +            "positionChanged", "(JIIII)V"); +    gPositionListener_PositionLostMethod = GetMethodIDOrDie(env, clazz, +            "positionLost", "(J)V");      return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));  } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 3c59bd1e3856..7a5b60493dcd 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -1064,6 +1064,12 @@ static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject c      proxy->allocateBuffers(surface);  } +static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz, +        jlong proxyPtr, jboolean enable) { +    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); +    proxy->setForceDark(enable); +} +  // ----------------------------------------------------------------------------  // FrameMetricsObserver  // ---------------------------------------------------------------------------- @@ -1177,6 +1183,7 @@ static const JNINativeMethod gMethods[] = {      { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },      { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },      { "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers }, +    { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },  };  static JavaVM* mJvm = nullptr; diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c15b7ee4fe04..109e65c4a1d0 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -285,10 +285,6 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,  static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,                                    jint limitUid, jobjectArray limitIfacesObj, jint limitTag,                                    jboolean useBpfStats) { -    ScopedUtfChars path8(env, path); -    if (path8.c_str() == NULL) { -        return -1; -    }      std::vector<std::string> limitIfaces;      if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { @@ -308,6 +304,11 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr          if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)              return -1;      } else { +        ScopedUtfChars path8(env, path); +        if (path8.c_str() == NULL) { +            ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str()); +            return -1; +        }          if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,                                           limitUid, path8.c_str()) < 0)              return -1; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 364393e1c649..1f958628374d 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -382,11 +382,10 @@ static int UnmountTree(const char* path) {      return 0;  } -static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& pkg_sandbox_dir, -        std::string* error_msg) { +static bool createPkgSandbox(uid_t uid, const std::string& package_name, std::string* error_msg) {      // Create /mnt/user/0/package/<package-name>      userid_t user_id = multiuser_get_user_id(uid); -    StringAppendF(&pkg_sandbox_dir, "/%d", user_id); +    std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);      if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {          *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());          return false; @@ -396,7 +395,7 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p          *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());          return false;      } -    StringAppendF(&pkg_sandbox_dir, "/%s", package_name); +    StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());      if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) {          *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());          return false; @@ -404,10 +403,51 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p      return true;  } +static bool mountPkgSpecificDir(const std::string& mntSourceRoot, +        const std::string& mntTargetRoot, const std::string& packageName, +        const char* dirName, std::string* error_msg) { +    std::string mntSourceDir = StringPrintf("%s/Android/%s/%s", +            mntSourceRoot.c_str(), dirName, packageName.c_str()); +    std::string mntTargetDir = StringPrintf("%s/Android/%s/%s", +            mntTargetRoot.c_str(), dirName, packageName.c_str()); +    if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(), +            nullptr, MS_BIND | MS_REC, nullptr)) == -1) { +        *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s", +                mntSourceDir.c_str(), mntTargetDir.c_str(), strerror(errno)); +        return false; +    } +    if (TEMP_FAILURE_RETRY(mount(nullptr, mntTargetDir.c_str(), +            nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) { +        *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", mntTargetDir.c_str()); +        return false; +    } +    return true; +} + +static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames, +        const std::vector<std::string>& volumeLabels, userid_t userId, std::string* error_msg) { +    for (auto& label : volumeLabels) { +        std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str()); +        std::string mntTarget = StringPrintf("/storage/%s", label.c_str()); +        if (label == "emulated") { +            StringAppendF(&mntSource, "/%d", userId); +            StringAppendF(&mntTarget, "/%d", userId); +        } +        for (auto& package : packageNames) { +            mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg); +            mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg); +            mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg); +        } +    } +    return true; +} +  // Create a private mount namespace and bind mount appropriate emulated  // storage for the given user.  static bool MountEmulatedStorage(uid_t uid, jint mount_mode, -        bool force_mount_namespace, std::string* error_msg, const char* package_name) { +        bool force_mount_namespace, std::string* error_msg, const std::string& package_name, +        const std::vector<std::string>& packages_for_uid, +        const std::vector<std::string>& visible_vol_ids) {      // See storage config details at http://source.android.com/tech/storage/      String8 storageSource; @@ -459,12 +499,25 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,                  return false;              }          } else { -            if (package_name == nullptr) { +            if (package_name.empty()) {                  return true;              } -            std::string pkgSandboxDir("/mnt/user"); -            if (!createPkgSandbox(uid, package_name, pkgSandboxDir, error_msg)) { -                return false; +            userid_t user_id = multiuser_get_user_id(uid); +            std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s", +                    user_id, package_name.c_str()); +            struct stat sb; +            bool sandboxAlreadyCreated = true; +            if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) { +                if (errno == ENOENT) { +                    ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str()); +                    sandboxAlreadyCreated = false; +                    if (!createPkgSandbox(uid, package_name, error_msg)) { +                        return false; +                    } +                } else { +                    ALOGE("Failed to lstat %s", pkgSandboxDir.c_str()); +                    return false; +                }              }              if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",                      nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) { @@ -472,6 +525,15 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,                          pkgSandboxDir.c_str(), strerror(errno));                  return false;              } +            // If the sandbox was already created by vold, only then set up the bind mounts for +            // pkg specific directories. Otherwise, leave as is and bind mounts will be taken +            // care of by vold later. +            if (sandboxAlreadyCreated) { +                if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids, +                        user_id, error_msg)) { +                    return false; +                } +            }          }      } else {          if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", @@ -611,7 +673,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi                               jlong permittedCapabilities, jlong effectiveCapabilities,                               jint mount_external, jstring java_se_info, jstring java_se_name,                               bool is_system_server, bool is_child_zygote, jstring instructionSet, -                             jstring dataDir, jstring packageName) { +                             jstring dataDir, jstring packageName, jobjectArray packagesForUid, +                             jobjectArray visibleVolIds) {    std::string error_msg;    auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) @@ -661,17 +724,33 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi      ALOGW("Native bridge will not be used because dataDir == NULL.");    } -  ScopedUtfChars* package_name = nullptr; -  const char* package_name_c_str = nullptr; +  std::string package_name_str("");    if (packageName != nullptr) { -    package_name = new ScopedUtfChars(env, packageName); -    package_name_c_str = package_name->c_str(); +    ScopedUtfChars package(env, packageName); +    package_name_str = package.c_str();    } else if (is_system_server) { -    package_name_c_str = "android"; +    package_name_str = "android"; +  } +  std::vector<std::string> packages_for_uid; +  if (packagesForUid != nullptr) { +    jsize count = env->GetArrayLength(packagesForUid); +    for (jsize i = 0; i < count; ++i) { +      jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i); +      ScopedUtfChars package(env, package_for_uid); +      packages_for_uid.push_back(package.c_str()); +    } +  } +  std::vector<std::string> visible_vol_ids; +  if (visibleVolIds != nullptr) { +    jsize count = env->GetArrayLength(visibleVolIds); +    for (jsize i = 0; i < count; ++i) { +      jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i); +      ScopedUtfChars vol(env, visible_vol_id); +      visible_vol_ids.push_back(vol.c_str()); +    }    }    bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg, -      package_name_c_str); -  delete package_name; +      package_name_str, packages_for_uid, visible_vol_ids);    if (!success) {      ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));      if (errno == ENOTCONN || errno == EROFS) { @@ -936,7 +1015,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(          jint runtime_flags, jobjectArray rlimits,          jint mount_external, jstring se_info, jstring se_name,          jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, -        jstring instructionSet, jstring appDataDir, jstring packageName) { +        jstring instructionSet, jstring appDataDir, jstring packageName, +        jobjectArray packagesForUid, jobjectArray visibleVolIds) {      jlong capabilities = 0;      // Grant CAP_WAKE_ALARM to the Bluetooth process. @@ -989,7 +1069,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(        SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,                         capabilities, capabilities,                         mount_external, se_info, se_name, false, -                       is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName); +                       is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName, +                       packagesForUid, visibleVolIds);      }      return pid;  } @@ -1003,7 +1084,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(        SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,                         permittedCapabilities, effectiveCapabilities,                         MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, -                       false, NULL, NULL, nullptr); +                       false, NULL, NULL, nullptr, nullptr, nullptr);    } else if (pid > 0) {        // The zygote process checks whether the child process has died or not.        ALOGI("System server process %d has been created", pid); @@ -1084,7 +1165,7 @@ static const JNINativeMethod gMethods[] = {      { "nativeSecurityInit", "()V",        (void *) com_android_internal_os_Zygote_nativeSecurityInit },      { "nativeForkAndSpecialize", -      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", +      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)I",        (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },      { "nativeForkSystemServer", "(II[II[[IJJ)I",        (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index f9f725a130ed..14ed9e6eeadb 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -397,6 +397,9 @@ message GlobalSettingsProto {          // Ordered GPU debug layer list          // i.e. <layer1>:<layer2>:...:<layerN>          optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; + +        // App will load ANGLE instead of native GLES drivers. +        optional SettingProto angle_enabled_app = 3;      }      optional Gpu gpu = 59; diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 9d5f0bcc54d9..ab50ad147107 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -130,6 +130,13 @@ message KeyguardControllerProto {      option (.android.msg_privacy).dest = DEST_AUTOMATIC;      optional bool keyguard_showing = 1; +    repeated KeyguardOccludedProto keyguard_occluded_states= 2; +} + +message KeyguardOccludedProto { +    option (.android.msg_privacy).dest = DEST_AUTOMATIC; + +    optional int32 display_id = 1;      optional bool keyguard_occluded = 2;  } diff --git a/core/proto/android/server/backup_chunks_metadata.proto b/core/proto/android/server/backup_chunks_metadata.proto new file mode 100644 index 000000000000..a375f02545c5 --- /dev/null +++ b/core/proto/android/server/backup_chunks_metadata.proto @@ -0,0 +1,134 @@ +/* + * 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 + */ + +syntax = "proto2"; +package com.android.server.backup.encryption.chunk; + +option java_outer_classname = "ChunksMetadataProto"; + +// Cipher type with which the chunks are encrypted. For now we only support AES/GCM/NoPadding, but +// this is for backwards-compatibility in case we need to change the default Cipher in the future. +enum CipherType { +    UNKNOWN_CIPHER_TYPE = 0; +    // Chunk is prefixed with a 12-byte nonce. The tag length is 16 bytes. +    AES_256_GCM = 1; +} + +// Checksum type with which the plaintext is verified. +enum ChecksumType { +    UNKNOWN_CHECKSUM_TYPE = 0; +    SHA_256 = 1; +} + +enum ChunkOrderingType { +    CHUNK_ORDERING_TYPE_UNSPECIFIED = 0; +    // The chunk ordering contains a list of the start position of each chunk in the encrypted file, +    // ordered as in the plaintext file. This allows us to recreate the original plaintext file +    // during decryption. We use this mode for full backups where the order of the data in the file +    // is important. +    EXPLICIT_STARTS = 1; +    // The chunk ordering does not contain any start positions, and instead each encrypted chunk in +    // the backup file is prefixed with its length. This allows us to decrypt each chunk but does +    // not give any information about the order. However, we use this mode for key value backups +    // where the order does not matter. +    INLINE_LENGTHS = 2; +} + +// Chunk entry (for local state) +message Chunk { +    // SHA-256 MAC of the plaintext of the chunk +    optional bytes hash = 1; +    // Number of bytes in encrypted chunk +    optional int32 length = 2; +} + +// List of the chunks in the blob, along with the length of each chunk. From this is it possible to +// extract individual chunks. (i.e., start position is equal to the sum of the lengths of all +// preceding chunks.) +// +// This is local state stored on the device. It is never sent to the backup server. See +// ChunkOrdering for how the device restores the chunks in the correct order. +// Next tag : 6 +message ChunkListing { +    repeated Chunk chunks = 1; + +    // Cipher algorithm with which the chunks are encrypted. +    optional CipherType cipher_type = 2; + +    // Defines the type of chunk order used to encode the backup file on the server, so that we can +    // consistently use the same type between backups. If unspecified this backup file was created +    // before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS. +    optional ChunkOrderingType chunk_ordering_type = 5; + +    // The document ID returned from Scotty server after uploading the blob associated with this +    // listing. This needs to be sent when uploading new diff scripts. +    optional string document_id = 3; + +    // Fingerprint mixer salt used for content defined chunking. This is randomly generated for each +    // package during the initial non-incremental backup and reused for incremental backups. +    optional bytes fingerprint_mixer_salt = 4; +} + +// Ordering information about plaintext and checksum. This is used on restore to reconstruct the +// blob in its correct order. (The chunk order is randomized so as to give the server less +// information about which parts of the backup are changing over time.) This proto is encrypted +// before being uploaded to the server, with a key unknown to the server. +message ChunkOrdering { +    // For backups where ChunksMetadata#chunk_ordering_type = EXPLICIT STARTS: +    // Ordered start positions of chunks. i.e., the file is the chunk starting at this position, +    // followed by the chunk starting at this position, followed by ... etc. You can compute the +    // lengths of the chunks by sorting this list then looking at the start position of the next +    // chunk after the chunk you care about. This is guaranteed to work as all chunks are +    // represented in this list. +    // +    // For backups where ChunksMetadata#chunk_ordering_type = INLINE_LENGTHS: +    // This field is unused. See ChunkOrderingType#INLINE_LENGTHS. +    repeated int32 starts = 1 [packed = true]; + +    // Checksum of plaintext content. (i.e., in correct order.) +    // +    // Each chunk also has a MAC, as generated by GCM, so this is NOT Mac-then-Encrypt, which has +    // security implications. This is an additional checksum to verify that once the chunks have +    // been reordered, that the file matches the expected plaintext. This prevents the device +    // restoring garbage data in case of a mismatch between the ChunkOrdering and the backup blob. +    optional bytes checksum = 2; +} + +// Additional metadata about a backup blob that needs to be synced to the server. This is used on +// restore to reconstruct the blob in its correct order. (The chunk order is randomized so as to +// give the server less information about which parts of the backup are changing over time.) This +// data structure is only ever uploaded to the server encrypted with a key unknown to the server. +// Next tag : 6 +message ChunksMetadata { +    // Cipher algorithm with which the chunk listing and chunks are encrypted. +    optional CipherType cipher_type = 1; + +    // Defines the type of chunk order this metadata contains. If unspecified this backup file was +    // created before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS. +    optional ChunkOrderingType chunk_ordering_type = 5 +    [default = CHUNK_ORDERING_TYPE_UNSPECIFIED]; + +    // Encrypted bytes of ChunkOrdering +    optional bytes chunk_ordering = 2; + +    // The type of algorithm used for the checksum of the plaintext. (See ChunkOrdering.) This is +    // for forwards compatibility in case we change the algorithm in the future. For now, always +    // SHA-256. +    optional ChecksumType checksum_type = 3; + +    // This used to be the plaintext tertiary key. No longer used. +    reserved 4; +}
\ No newline at end of file diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto new file mode 100644 index 000000000000..941c81fbb8df --- /dev/null +++ b/core/proto/android/server/usagestatsservice.proto @@ -0,0 +1,100 @@ +/* + * 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. + */ + +syntax = "proto2"; +package com.android.server.usage; +import "frameworks/base/core/proto/android/content/configuration.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + +option java_multiple_files = true; + +message IntervalStatsProto { +  message StringPool { +    optional int32 size = 1; +    repeated string strings = 2; +  } + +  message CountAndTime { +    optional int32 count = 1; +    optional int64 time_ms = 2; +  } + +  // Stores the relevant information from a UsageStats +  message UsageStats { +    message ChooserAction { +      message CategoryCount { +        optional string name = 1; +        optional int32 count = 3; +      } +      optional string name = 1; +      repeated CategoryCount counts = 3; +    } +    optional string package = 1; +    // package_index contains the index + 1 of the package name in the string pool +    optional int32 package_index = 2; +    optional int64 last_time_active_ms = 3; +    optional int64 total_time_active_ms = 4; +    optional int32 last_event = 5; +    optional int32 app_launch_count = 6; +    repeated ChooserAction chooser_actions = 7; +  } + +  // Stores the relevant information an IntervalStats will have about a Configuration +  message Configuration { +    optional .android.content.ConfigurationProto config = 1; +    optional int64 last_time_active_ms = 2; +    optional int64 total_time_active_ms = 3; +    optional int32 count = 4; +    optional bool active = 5; +  } + +  // Stores the relevant information from a UsageEvents.Event +  message Event { +    optional string package = 1; +    // package_index contains the index + 1 of the package name in the string pool +    optional int32 package_index = 2; +    optional string class = 3; +    // class_index contains the index + 1 of the class name in the string pool +    optional int32 class_index = 4; +    optional int64 time_ms = 5; +    optional int32 flags = 6; +    optional int32 type = 7; +    optional .android.content.ConfigurationProto config = 8; +    optional string shortcut_id = 9; +    optional int32 standby_bucket = 11; +    optional string notification_channel = 12; +    // notification_channel_index contains the index + 1 of the channel name in the string pool +    optional int32 notification_channel_index = 13; +  } + +  // The following fields contain supplemental data used to build IntervalStats, such as a string +  // pool. +  optional int64 end_time_ms = 1; +  // stringpool contains all the package and class names used by UsageStats and Event +  // They will hold a number that is equal to the index + 1 of their string in the pool +  optional StringPool stringpool = 2; + +  // The following fields contain aggregated usage stats data +  optional CountAndTime interactive = 10; +  optional CountAndTime non_interactive = 11; +  optional CountAndTime keyguard_shown = 12; +  optional CountAndTime keyguard_hidden = 13; + +  // The following fields contain listed usage stats data +  repeated UsageStats packages = 20; +  repeated Configuration configurations = 21; +  repeated Event event_log = 22; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f97873e566a4..f654ce231161 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -941,7 +941,6 @@           Requesting this by itself is not sufficient to give you           location access.           <p>Protection level: dangerous -         @hide      -->      <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"          android:permissionGroup="android.permission-group.LOCATION" @@ -1186,9 +1185,9 @@          android:priority="700" />      <!-- Required to be able to access the camera device. -         <p>This will automatically enforce the <a -         href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> -         <uses-feature>}</a> manifest element for <em>all</em> camera features. +         <p>This will automatically enforce the +         <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> +         uses-feature</a> manifest element for <em>all</em> camera features.           If you do not require all camera features or can properly operate if a camera           is not available, then you must modify your manifest as appropriate in order to           install on devices that don't support all camera features.</p> @@ -4150,6 +4149,15 @@      <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"          android:protectionLevel="signature" /> +    <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. --> +    <permission android:name="android.permission.BIND_SMS_APP_SERVICE" +        android:protectionLevel="signature" /> + +    <!-- @hide Permission that allows background clipboard access. +         <p>Not for use by third-party applications. --> +    <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" +        android:protectionLevel="signature" /> +      <application android:process="system"                   android:persistent="true"                   android:hasCode="false" @@ -4465,14 +4473,6 @@              android:permission="android.permission.LOCATION_HARDWARE"              android:exported="false" /> -        <service android:name="com.android.internal.backup.LocalTransportService" -                android:permission="android.permission.CONFIRM_FULL_BACKUP" -                android:exported="false"> -            <intent-filter> -                <action android:name="android.backup.TRANSPORT_HOST" /> -            </intent-filter> -        </service> -          <service android:name="com.android.server.MountServiceIdler"                   android:exported="true"                   android:permission="android.permission.BIND_JOB_SERVICE" > diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 3b124dabed88..5028150edda2 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie herken nie"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk is gestaaf"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gesig is gestaaf"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gesig is gestaaf; druk asseblief bevestig"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Vingerafdrukhardeware is nie beskikbaar nie."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Gesiguittelling is bereik. Probeer weer."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Gesig kan nie geberg word nie."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Gesighandeling is gekanselleer."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gesigstawing is deur gebruiker gekanselleer."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogings. Probeer later weer."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogings. Gesigstawingsensor is gedeaktiveer."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer weer."</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 3cd1b5024d20..217d6317c328 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"አልታወቀም"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ፊት ተረጋግጧል"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ፊት ተረጋግጧል፣ እባክዎ አረጋግጥን ይጫኑ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"የጣት አሻራ ሃርድዌር አይገኝም።"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"የጣት አሻራ ሊከማች አይችልም። እባክዎ አሁን ያለውን የጣት አሻራ ያስወግዱ።"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"የጣት አሻራ ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"የፊት ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ፊት ሊከማች አይችልም።"</string>      <string name="face_error_canceled" msgid="283945501061931023">"የፊት ሥርዓተ ክወና ተሰርዟል።"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ፊትን ማረጋገጥ በተጠቃሚ ተሰርዟል።"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"በጣም ብዙ ሙከራዎች። የፊት ማረጋገጫ ተሰናክሏል።"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"እንደገና ይሞክሩ።"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index cf3b0351959e..c11279a428e3 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -540,10 +540,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"تم مصادقة بصمة الإصبع"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"تمّت مصادقة الوجه"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"تمّت مصادقة الوجه، يُرجى الضغط على \"تأكيد\"."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"جهاز بصمة الإصبع غير متاح."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"يتعذر تخزين بصمة الإصبع؛ يرجى إزالة إحدى البصمات المخزنة."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"تم بلوغ مهلة إدخال بصمة الإصبع. أعد المحاولة."</string> @@ -580,8 +578,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"انتهت مهلة التعرُّف على الوجه. أعِد المحاولة."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"يتعذَّر حفظ الوجه."</string>      <string name="face_error_canceled" msgid="283945501061931023">"تمّ إلغاء عملية مصادقة الوجه."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ألغَى المستخدم مصادقة الوجه."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"تمّ إجراء محاولات كثيرة. أعِد المحاولة لاحقًا."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"تمّ إجراء محاولات كثيرة. ميزة مصادقة الوجه متوقفة."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"يُرجى إعادة المحاولة."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 997486778665..5a0a7ec253a0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -312,7 +312,7 @@      <string name="permgrouprequest_visual" msgid="6907523945030290376">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ ফট’ আৰু ভিডিঅ’সমূহ এক্সেছ কৰিবলৈ দিবনে?"</string>      <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ৱিণ্ড\' সমল বিচাৰি উলিয়াওক"</string>      <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"আপুনি যোগাযোগ কৰি থকা ৱিণ্ড\'খনৰ সমল পৰীক্ষা কৰক।"</string> -    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"স্পৰ্শৰদ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰক"</string> +    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰক"</string>      <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"টেপ কৰা বস্তুসমূহ ডাঙৰকৈ কোৱা হ\'ব আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ দি স্ক্ৰীণ অন্বেষণ কৰিব পাৰিব।"</string>      <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"আপুনি লিখা পাঠ নিৰীক্ষণ কৰক"</string>      <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ক্ৰেডিট কাৰ্ডৰ নম্বৰ আৰু পাছৱৰ্ডৰ দৰে ব্যক্তিগত ডেটা অন্তৰ্ভুক্ত হ\'ব পাৰে।"</string> @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ\'ল"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ\'ল, অনুগ্ৰহ কৰি ‘নিশ্চিত কৰক’ বুটামটো টিপক"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ নাই।"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ফিংগাৰপ্ৰিণ্ট সঞ্চয় কৰিব পৰা নগ\'ল। পূর্বে সঞ্চিত ফিংগাৰপ্ৰিণ্ট এটা আঁতৰাওক।"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ফিংগাৰপ্ৰিণ্ট গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"মুখমণ্ডল গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"মুখমণ্ডল সঞ্চয় কৰিব নোৱাৰি।"</string>      <string name="face_error_canceled" msgid="283945501061931023">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ব্যৱহাৰকাৰীয়ে মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ বাতিল কৰিছে।"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"অত্যধিক প্ৰয়াস। মুখমণ্ডলৰ জৰিয়তে সত্যাপন অক্ষম কৰা হ’ল।"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"আকৌ চেষ্টা কৰক।"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 3236b5237c8e..af65bbbf35e8 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmır"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmaq izi doğrulandı"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Üz doğrulandı"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Üz təsdiq edildi, təsdiq düyməsinə basın"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmaq izi üçün avadanlıq yoxdur."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmaq izi saxlana bilməz. Lütfən, mövcud barmaq izini silin."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmaq izinin vaxtı başa çatdı. Yenidən cəhd edin."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Üz proqramı taymerinin vaxtı bitdi. Yenidən cəhd edin."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Üz bərpa edilmədi."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Üz əməliyyatı ləğv edildi."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Üz dorğulaması istifadəçi tərəfindən ləğv edildi."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Həddindən çox cəhd. Sonraya saxlayın."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Həddindən çox cəhd. Üz identifikasiyası deaktiv edildi."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Yenidən cəhd edin."</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 2bbf9b276349..805082a1785e 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je potvrđeno"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je potvrđeno. Pritisnite Potvrdi"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vreme za proveru lica. Probajte ponovo."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće sačuvati lice."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Obrada lica je otkazana."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Korisnik je otkazao potvrdu lica."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Probajte ponovo kasnije."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Više pokušaja. Potvrda identiteta je onemogućena."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Probajte ponovo."</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 0ec976fedef6..7692220c70dc 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распазнана"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Адбітак пальца распазнаны"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Твар распазнаны"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Твар распазнаны. Націсніце, каб пацвердзіць"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратныя сродкі адбіткаў пальцаў недаступныя."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Адбіткі пальцаў нельга захаваць. Выдаліце існы адбітак."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час чакання адбіткаў пальцаў выйшаў. Паспрабуйце яшчэ раз."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Час чакання твару выйшаў. Паўтарыце спробу."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Не ўдалося захаваць твар."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Распазнаванне твару скасавана."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Распазнаванне твару скасавана карыстальнікам."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Занадта шмат спроб. Паўтарыце спробу пазней."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Занадта шмат спроб. Аўтэнтыфікацыя твару адключана"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Паўтарыце спробу."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 3af930f6db4d..33c489839002 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Не е разпознато"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатъкът е удостоверен"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицето е удостоверено"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицето е удостоверено. Моля, натиснете „Потвърждаване“"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардуерът за отпечатъци не е налице."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатъкът не може да бъде съхранен. Моля, премахнете съществуващ."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Времето за изчакване за отпечатък изтече. Опитайте отново."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Времето за изчакване изтече. Опитайте отново."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да бъде съхранено."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Операцията с лице е анулирана."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Удостоверяв. на лицето е анулирано от потребителя."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Твърде много опити. Опитайте отново по-късно."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Твърде много опити. Удост. с лице е деактивирано."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Опитайте отново."</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 301bcc07876f..f0787b44a5b2 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ফেস যাচাই করা হয়েছে"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ফেস যাচাই করা হয়েছে, \'কনফার্ম করুন\' বোতাম প্রেস করুন"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার অনুপলব্ধ৷"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"আঙ্গুলের ছাপ সংরক্ষণ করা যাবে না৷ অনুগ্রহ করে একটি বিদ্যমান আঙ্গুলের ছাপ সরান৷"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"আঙ্গুলের ছাপ নেওয়ার সময়সীমা শেষ হযেছে৷ আবার চেষ্টা করুন৷"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ফেসের ছাপ নেওয়ার সময়সীমা শেষ৷ আবার চেষ্টা করুন৷"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ফেস স্টোর করা যাবে না।"</string>      <string name="face_error_canceled" msgid="283945501061931023">"ফেস অপারেশন বাতিল করা হয়েছে৷"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ফেস যাচাইকরণ ব্যবহারকারীর দ্বারা বাতিল করা হয়েছে।"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"অনেকবার চেষ্টা করা হয়েছে৷ ফেস যাচাইকরণ বন্ধ আছে।"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"আবার চেষ্টা করুন।"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index e6fde5b1f3bc..e210d90e4c2b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je provjereno"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je provjereno, pritisnite dugme za potvrdu"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta se ne može pohraniti. Uklonite postojeći otisak prsta."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vrijeme za prepoznavanje otiska prsta je isteklo. Pokušajte ponovo."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Vrijeme za prepoznavanje lica je isteklo. Pokušajte ponovo."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Prepoznavanje lica je otkazano."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Korisnik je otkazao provjeru lica."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 9318715935e5..b1d4994080c0 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta digital s\'ha autenticat"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Cara autenticada"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Cara autenticada; prem el botó per confirmar"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El maquinari per a empremtes digitals no està disponible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"S\'ha esgotat el temps d\'espera. Torna-ho a provar."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"La cara no es pot desar."</string>      <string name="face_error_canceled" msgid="283945501061931023">"S\'ha cancel·lat el reconeixement facial."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticació facial cancel·lada per l\'usuari."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Massa intents. Torna-ho a provar més tard."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Massa intents. Autenticació facial desactivada."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Torna-ho a provar."</string> @@ -814,8 +811,8 @@      <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string>      <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Targeta SIM no utilitzable."</string>      <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La targeta SIM està desactivada permanentment.\n Contacta amb el teu proveïdor de serveis sense fil per obtenir-ne una altra."</string> -    <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Ruta anterior"</string> -    <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Ruta següent"</string> +    <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Pista anterior"</string> +    <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Pista següent"</string>      <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Posa en pausa"</string>      <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Reprodueix"</string>      <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Atura"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 45c57d0007d4..a537d6d2f9ca 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznáno"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisk byl ověřen"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Obličej byl ověřen"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Obličej byl ověřen, stiskněte tlačítko pro potvrzení"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Není k dispozici hardware ke snímání otisků prstů."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisk prstu nelze uložit. Odstraňte existující otisk prstu."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit sejmutí otisku prstu vypršel. Zkuste to znovu."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Limit ověření obličeje vypršel. Zkuste to znovu."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Obličej nelze uložit."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operace snímání obličeje byla zrušena."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ověření obličeje bylo zrušeno uživatelem."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Příliš mnoho pokusů. Zkuste to později."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Příliš mnoho pokusů. Ověření obličeje je zakázáno."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Zkuste to znovu."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index f279f0bb650d..28c08b151b12 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke genkendt"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeraftrykket blev godkendt"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansigtet er godkendt"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansigtet er godkendt. Tryk på Bekræft."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardwaren til fingeraftryk er ikke tilgængelig."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Ansigtsgenkendelse fik timeout. Prøv igen."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Ansigtet kan ikke gemmes."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Ansigtshandlingen blev annulleret."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ansigtsgodkendelsen blev annulleret af brugeren."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Du har prøvet for mange gange. Prøv igen senere."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøg – Ansigtsgenkendelse deaktiveret."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igen."</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 7ec4401180db..4a2efbda2700 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nicht erkannt"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerabdruck wurde authentifiziert"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gesicht authentifiziert"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gesicht authentifiziert, bitte bestätigen"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerabdruckhardware nicht verfügbar"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entferne einen vorhandenen Fingerabdruck."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Bitte versuche es noch einmal."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Zeitüberschreitung für Gesicht. Versuch es erneut."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Gesicht kann nicht gespeichert werden."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Gesichtserkennung abgebrochen."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gesichtsauthentifizierung vom Nutzer abgebrochen."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Zu viele Versuche. Versuch es später noch einmal."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zu viele Versuche. Gesichtserkennung deaktiviert."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Versuch es noch einmal."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index f2309e84b71b..04b9749852fd 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Δεν αναγνωρίστηκε"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Έγινε έλεγχος ταυτότητας προσώπου"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Έγινε έλεγχος ταυτότητας προσώπου, πατήστε \"Επιβεβαίωση\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Ο εξοπλισμός μοναδικού χαρακτηριστικού δεν είναι διαθέσιμος."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Δεν είναι δυνατή η αποθήκευση μοναδικού χαρακτηριστικού. Καταργήστε το υπάρχον μοναδικό χαρακτηριστικό."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Λήξη χρονικού ορίου μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Λήξη χρονικού ορίου προσώπου. Δοκιμάστε ξανά."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Δεν είναι δυνατή η αποθήκευση του προσώπου."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Η ενέργεια προσώπου ακυρώθηκε."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ο έλεγχος ταυτότητας προσώπου ακυρώθηκε από τον χρήστη."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Πολλές προσπάθειες. Αποτυχία ελέγ. ταυτ. προσώπου."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Δοκιμάστε ξανά."</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1eeb1c33c4e0..85923550bc30 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 699e50f33050..1e075f8c60f8 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 1eeb1c33c4e0..85923550bc30 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 1eeb1c33c4e0..85923550bc30 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 63726f8dc906..91380980c5c2 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognized"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated, please press confirm"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint time out reached. Try again."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Face operation canceled."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication canceled by user."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 6a49e033d811..6176b7b57d75 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoció"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Se autenticó la huella digital"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Se autenticó el rostro"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Se autenticó el rostro; presiona Confirmar"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware para detectar huellas digitales no está disponible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una de las existentes."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Finalizó el tiempo de espera para la huella digital. Vuelve a intentarlo."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Se agotó el tiempo. Vuelve a intentarlo."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"No se puede almacenar el rostro."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Se canceló el reconocimiento facial."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"El usuario canceló la autenticación de rostro."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Vuelve a intentarlo."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index b62f4c9b435e..dd766f765940 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoce"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Se ha autenticado la huella digital"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Cara autenticada"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Se ha autenticado la cara, pulsa para confirmar"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware de huella digital no está disponible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una ya creada."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Se ha alcanzado el tiempo de espera de la huella digital. Vuelve a intentarlo."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Has sobrepasado el tiempo. Inténtalo de nuevo."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"No se pueden registrar más caras."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Se ha cancelado el reconocimiento facial."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"El usuario ha cancelado la autenticación de la cara."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Inténtalo de nuevo."</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 8f011f859c35..650fcb662c60 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tuvastatud"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sõrmejälg autenditi"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Nägu on autenditud"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Nägu on autenditud, vajutage käsku Kinnita"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sõrmejälje riistvara pole saadaval."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sõrmejälge ei saa salvestada. Eemaldage olemasolev sõrmejälg."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sõrmejälje riistvara taimeri ajalõpp. Proovige uuesti."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Näotuvastuse taimeri ajalõpp. Proovige uuesti."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nägu ei saa salvestada."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Näotuvastuse toiming tühistati."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Kasutaja tühistas näo autentimise."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Liiga palju katseid. Proovige hiljem uuesti."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liiga palju katseid. Näotuvastus on keelatud."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Proovige uuesti."</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index a070cc523e93..6a6fdbf91038 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ez da ezagutu"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentifikatu da hatz-marka"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Autentifikatu da aurpegia"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Autentifikatu da aurpegia; sakatu Berretsi"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hatz-markaren hardwarea ez dago erabilgarri."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Gainditu da aurpegiak prozesatzeko denbora-muga. Saiatu berriro."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Ezin da gorde aurpegia."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Utzi da aurpegiaren bidezko eragiketa."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Erabiltzaileak utzi du aurpegi-autentifikazioa."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Saiakera gehiegi egin dituzu. Desgaitu egin da autentifikazioa."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Saiatu berriro."</string> @@ -1139,7 +1136,7 @@      <string name="aerr_application_repeated" msgid="3146328699537439573">"Behin eta berriz gelditzen ari da <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>      <string name="aerr_process_repeated" msgid="6235302956890402259">"Behin eta berriz gelditzen ari da <xliff:g id="PROCESS">%1$s</xliff:g>"</string>      <string name="aerr_restart" msgid="7581308074153624475">"Ireki aplikazioa berriro"</string> -    <string name="aerr_report" msgid="5371800241488400617">"Bidali iritzia"</string> +    <string name="aerr_report" msgid="5371800241488400617">"Bidali oharrak"</string>      <string name="aerr_close" msgid="2991640326563991340">"Itxi"</string>      <string name="aerr_mute" msgid="1974781923723235953">"Ezkutatu gailua berrabiarazi arte"</string>      <string name="aerr_wait" msgid="3199956902437040261">"Itxaron"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 3101b7262df0..2310f9eb3407 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"شناسایی نشد"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"اثر انگشت احراز هویت شد"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"چهره احراز هویت شد"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"چهره احراز هویت شد، لطفاً تأیید را فشار دهید"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"سختافزار اثرانگشت در دسترس نیست."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ذخیره اثر انگشت ممکن نیست. لطفاً یک اثر انگشت موجود را حذف کنید."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"مهلت زمانی شناسایی چهره تمام شد. دوباره امتحان کنید"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"نمیتوان چهره را ذخیره کرد."</string>      <string name="face_error_canceled" msgid="283945501061931023">"عملیات شناسایی چهره لغو شد."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"احراز هویت چهره توسط کاربر لغو شد."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"چندین تلاش ناموفق. احراز هویت با چهره غیرفعال شد."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"دوباره امتحان کنید."</string> @@ -900,7 +897,7 @@      <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"ماندن در این صفحه"</string>      <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nمطمئنید میخواهید این صفحه را ترک کنید؟"</string>      <string name="save_password_label" msgid="6860261758665825069">"تأیید"</string> -    <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگنمایی و کوچکنمایی، دو بار ضربه بزنید."</string> +    <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای نزدیکنمایی و دورنمایی، دو بار ضربه بزنید."</string>      <string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>      <string name="setup_autofill" msgid="7103495070180590814">"راهاندازی تکمیل خودکار"</string>      <string name="autofill_window_title" msgid="4107745526909284887">"تکمیل خودکار با <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 346992f89b85..4f2531c838fb 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tunnistettu"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sormenjälki tunnistettu"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Kasvot tunnistettu"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Kasvot tunnistettu, valitse Vahvista"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sormenjälkilaitteisto ei ole käytettävissä."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sormenjälkeä ei voida tallentaa. Poista aiemmin lisätty sormenjälki."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sormenjälkitunnistimen toiminta aikakatkaistiin. Yritä uudelleen."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Kasvotoiminto aikakatkaistiin. Yritä uudelleen."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Kasvoja ei voi tallentaa."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Kasvotoiminto peruutettu"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Käyttäjä peruutti kasvojentunnistuksen."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liikaa yrityksiä. Kasvojentodennus ei käytössä."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Yritä uudelleen."</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 16fd62a2bedd..39889ec88b9b 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Données biométriques non reconnues"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Visage authentifié"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Visage authentifié, veuillez appuyer sur le bouton Confirmer"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empreinte digitale ne peut pas être enregistrée. Veuillez supprimer une empreinte existante."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Le temps attribué pour lire l\'empreinte est écoulé. Veuillez essayer de nouveau."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Temps de reconn. visage écoulé. Veuillez réessayer."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker le visage."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance du visage annulée."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Authentification du visage annulée par l\'utilisateur"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Veuillez réessayer plus tard."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop de tentatives. Capt. reconn. visage désactivé."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 76eed1f5782c..975941563ea7 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Non reconnu"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Visage authentifié"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Visage authentifié, veuillez appuyer sur \"Confirmer\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossible d\'enregistrer l\'empreinte numérique. Veuillez supprimer une empreinte."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Délai de détection de l\'empreinte numérique expiré. Veuillez réessayer."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Délai de détection du visage expiré. Réessayez."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker les informations du visage."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance faciale annulée."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Authentification faciale annulée par l\'utilisateur."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Réessayez plus tard."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop d\'essais. Authentification faciale désactivée."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index f64491986cdb..318dd3ed7aa7 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Non se recoñeceu"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autenticouse a impresión dixital"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Autenticouse a cara"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Autenticouse a cara, preme Confirmar"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impresión dixital non dispoñible."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Non se pode almacenar a impresión dixital. Elimina unha impresión dixital existente."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Esgotouse o tempo de espera da impresión dixital. Téntao de novo."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Esgotouse o tempo de espera. Téntao de novo."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Non se puido almacenar a cara."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Cancelouse a operación relacionada coa cara"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"O usuario cancelou a autenticación da cara."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Téntao de novo máis tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autenticación desactivada."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Téntao de novo."</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 4ea553cb0043..13090c6bbb48 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ચહેરા પ્રમાણિત"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ચહેરા પ્રમાણિત, કૃપા કરીને કન્ફર્મ કરો"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ફિંગરપ્રિન્ટ હાર્ડવેર ઉપલબ્ધ નથી."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ફિંગરપ્રિન્ટ સંગ્રહિત કરી શકાતી નથી. કૃપા કરીને અસ્તિત્વમાંની ફિંગરપ્રિન્ટ દૂર કરો."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ફિંગરપ્રિન્ટનો સમય બાહ્ય થયો. ફરી પ્રયાસ કરો."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ચહેરા માટેનો સમય સમાપ્ત થયો. ફરી પ્રયાસ કરો."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ચહેરો સંગ્રહિત કરી શકાશે નહીં."</string>      <string name="face_error_canceled" msgid="283945501061931023">"ચહેરા સંબંધિત કાર્યવાહી રદ કરવામાં આવી છે."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"વપરાશકર્તાએ ચહેરા પ્રમાણીકરણ રદ કર્યુ."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ઘણા બધા પ્રયત્નો. થોડા સમય પછી ફરી પ્રયાસ કરો."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ઘણા બધા પ્રયત્નો. ચહેરાનું પ્રમાણીકરણ બંધ કરવામાં આવ્યું છે."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ફરી પ્રયાસ કરો."</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index c24b0ae0ca43..bebd4896e89b 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -530,10 +530,8 @@      <!-- no translation found for biometric_not_recognized (5770511773560736082) -->      <skip />      <string name="fingerprint_authenticated" msgid="5309333983002526448">"फ़िंगरप्रिंट की पुष्टि हो गई"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"चेहरे की पहचान की गई"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string> @@ -570,8 +568,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"चेहरे की पहचान का समय खत्म हुआ. फिर से कोशिश करें."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"चेहरा सेव करने की सीमा पूरी हो गई है."</string>      <string name="face_error_canceled" msgid="283945501061931023">"चेहरा पहचानने की कार्रवाई रद्द की गई."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"उपयोगकर्ता ने चेहरे की पहचान रद्द कर दी."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"कई बार कोशिश की गई. बाद में कोशिश करें."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"कई बार कोशिश की. चेहरा पहचानने की सुविधा बंद हुई."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"फिर से कोशिश करें."</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 6a9d307070d9..839d423ea16f 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentificirano otiskom prsta"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je autentificirano"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je autentificirano, pritisnite Potvrdi"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta nije pohranjen. Uklonite postojeći otisak prsta."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Isteklo je vrijeme čekanja za otisak prsta. Pokušajte ponovo."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vrijeme čekanja za lice. Pokušajte opet"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Otkazana je radnja s licem."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentifikaciju lica otkazao je korisnik."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 474c73a287f4..bc54bfa2f913 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nem ismerhető fel"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Ujjlenyomat hitelesítve"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Arc hitelesítve"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Arc hitelesítve; nyomja meg a Megerősítés lehetőséget"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Az ujjlenyomathoz szükséges hardver nem érhető el."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Az ujjlenyomat nem tárolható. Távolítson el egy meglévő ujjlenyomatot."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Az ujjlenyomat-beolvasási műveletkor időtúllépés történt. Próbálkozzon újra."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Időtúllépés az arcbeolvasásnál. Próbálja újra."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Az arc nem tárolható."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Az arccal kapcsolatos művelet törölve."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Az arc hitelesítését a felhasználó visszavonta."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Túl sok próbálkozás. Próbálja újra később."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Túl sok próbálkozás. Arcfelismerés letiltva."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Próbálkozzon újra."</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index b9e6c6263e96..4a828fa3148a 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Չհաջողվեց ճանաչել"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Մատնահետքը նույնականացվեց"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Դեմքը ճանաչվեց"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Դեմքը ճանաչվեց: Սեղմեք «Հաստատել»:"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Մատնահետքի սարքն անհասանելի է:"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Ժամանակը սպառվել է: Նորից փորձեք:"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Դեմքը հնարավոր չէ պահել։"</string>      <string name="face_error_canceled" msgid="283945501061931023">"Դեմքի ճանաչումը չեղարկվել է։"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Դեմքի ճանաչումը չեղարկվել է օգտատիրոջ կողմից:"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Չափից շատ փորձեր եք կատարել: Փորձեք ավելի ուշ:"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Չափից շատ փորձեր եք կատարել: Դեմքի ճանաչման գործառույթն անջատվել է։"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Նորից փորձեք:"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 8298a18eae03..167082db7a01 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sidik jari diautentikasi"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Wajah diautentikasi"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Wajah diautentikasi, silakan tekan konfirmasi"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware sidik jari tidak tersedia."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sidik jari tidak dapat disimpan. Hapus sidik jari yang ada."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Waktu sidik jari habis. Coba lagi."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Waktu tunggu wajah habis. Harap coba lagi."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Pemrosesan wajah dibatalkan."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentikasi wajah dibatalkan oleh pengguna."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percobaan. Coba lagi nanti."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu sering dicoba. Autentikasi wajah dinonaktifkan."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Coba lagi."</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 2649a1a05b1f..0c7e6b8ed5fd 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Þekktist ekki"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingrafar staðfest"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Andlit staðfest"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Andlit staðfest, ýttu til að staðfesta"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingrafarsvélbúnaður ekki til staðar."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ekki er hægt að vista fingrafarið. Fjarlægðu eitthvert af fingraförunum sem fyrir eru."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tímamörk runnu út fyrir fingrafar. Reyndu aftur."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tímamörk runnu út fyrir andlit. Reyndu aftur."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Ekki tókst að geyma andlit."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Hætt við andlitsgreiningu."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Notandi hætti við andlitsgreiningu."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Of margar tilraunir. Reyndu aftur síðar."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Of margar tilraunir. Slökkt á andlitsgreiningu."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Reyndu aftur."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 5c28097f3dc2..a6d5d2394de5 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Non riconosciuto"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impronta digitale autenticata"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Volto autenticato"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Volto autenticato, premi Conferma"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware per l\'impronta digitale non disponibile."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossibile memorizzare l\'impronta digitale. Rimuovi un\'impronta esistente."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timeout impronta digitale. Riprova."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Timeout operazione associata al volto. Riprova."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Il volto non può essere memorizzato."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operazione associata al volto annullata."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticazione del volto annullata dall\'utente."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Troppi tentativi. Riprova più tardi."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Troppi tentativi. Autenticazione disattivata."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Riprova."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 5dd16172d3c3..48933f99f727 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"לא זוהתה"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"טביעת האצבע אומתה"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"זיהוי הפנים בוצע"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"זיהוי הפנים בוצע. יש ללחוץ על אישור"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"החומרה בשביל טביעת אצבע אינה זמינה."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"חלף הזמן הקצוב לזיהוי הפנים. יש לנסות שוב."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"לא ניתן לשמור את הפנים."</string>      <string name="face_error_canceled" msgid="283945501061931023">"פעולת הפנים בוטלה."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"זיהוי הפנים בוטל על ידי המשתמש."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"יותר מדי ניסיונות. אימות הפנים הושבת."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"יש לנסות שוב."</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 7b53ed4e44d2..994039c17741 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"認識されませんでした"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋認証を完了しました"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"顔を認証しました"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"顔を認証しました。[確認] を押してください"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋ハードウェアは使用できません。"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋を保存できません。既存の指紋を削除してください。"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"読み取りのタイムアウトです。もう一度お試しください。"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"顔の情報を保存できません。"</string>      <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"顔の認証がユーザーによりキャンセルされました。"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"試行回数の上限です。顔認証は無効になりました。"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"もう一度お試しください。"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 722629698789..a9ce748de573 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"არ არის ამოცნობილი"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"თითის ანაბეჭდი ავტორიზებულია"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"სახე ავტორიზებულია"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"სახე ავტორიზებულია, დააჭირეთ დადასტურებას"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"თითის ანაბეჭდის აპარატურა არ არის ხელმისაწვდომი."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"თითის ანაბეჭდის შენახვა ვერ ხერხდება. გთხოვთ, ამოშალოთ არსებული თითის ანაბეჭდი."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"თითის ანაბეჭდის ლოდინის დრო ამოიწურა. სცადეთ ხელახლა."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"სახის ამოცნობის დრო ამოიწურა. ცადეთ ხელახლა."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"სახის შენახვა ვერ მოხერხდა."</string>      <string name="face_error_canceled" msgid="283945501061931023">"სახის ამოცნობა გაუქმდა."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"სახის ავტორიზაცია გაუქმდა მომხმარებლის მიერ."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"დაფიქსირდა ბევრი მცდელობა. ცადეთ მოგვიანებით."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"დაფიქსირდა ბევრი მცდელობა. სახის ამოცნობა გაითიშა."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ცადეთ ხელახლა."</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 457933e16444..a8b527bb1f97 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Танылмады"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Саусақ ізі аутентификацияланды"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Бет танылды"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Бет танылды, \"Растау\" түймесін басыңыз"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Саусақ ізі жабдығы қолжетімді емес."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Саусақ ізін сақтау мүмкін емес. Бар саусақ ізін жойыңыз."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Саусақ ізін күту уақыты бітті. Әрекетті қайталаңыз."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Күту уақыты бітті. Әрекетті қайталаңыз."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Бетті сақтау мүмкін емес."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Бетті танудан бас тартылды."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Пайдаланушы бетті тану әрекетінен бас тартты."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Тым көп әрекет жасалды. Кейінірек қайталаңыз."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Тым көп әрекет жасалды. Бетті тану функциясы өшірілді."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Қайталап көріңіз."</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index b3a3a01c7564..2620ce45d234 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"មិនអាចសម្គាល់បានទេ"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"បានផ្ទៀងផ្ទាត់ស្នាមម្រាមដៃ"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"បានផ្ទៀងផ្ទាត់មុខ"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"បានផ្ទៀងផ្ទាត់មុខ សូមចុចបញ្ជាក់"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ផ្នែករឹងស្នាមម្រាមដៃមិនមានទេ។"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"មិនអាចផ្ទុកស្នាមម្រាមដៃទេ។ សូមយកស្នាមម្រាមដៃដែលមានស្រាប់ចេញ។"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ការផ្តិតម្រាមដៃបានអស់ពេល។ សូមព្យាយាមម្តងទៀត។"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ការសម្គាល់ផ្ទៃមុខបានអស់ម៉ោង។ សូមព្យាយាមម្ដងទៀត។"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"មិនអាចរក្សាទុកផ្ទៃមុខបានទេ។"</string>      <string name="face_error_canceled" msgid="283945501061931023">"បានបោះបង់ប្រតិបត្តិការចាប់ផ្ទៃមុខ។"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ការផ្ទៀងផ្ទាត់មុខត្រូវបានបោះបង់ដោយអ្នកប្រើប្រាស់។"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ព្យាយាមចូលច្រើនពេកហើយ។ បានបិទការផ្ទៀងផ្ទាត់ផ្ទៃមុខ។"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"សូមព្យាយាមម្ដងទៀត។"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 2dc0bb1cfcec..1b83ec2e621c 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ, ದೃಢೀಕರಣವನ್ನು ಒತ್ತಿ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ಬೆರಳಚ್ಚು ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ಬೆರಳಚ್ಚು ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಬೆರಳಚ್ಚು ತೆಗೆದುಹಾಕಿ."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ಬೆರಳಚ್ಚು ಅವಧಿ ಮೀರಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ಮುಖ ಸಮಯದ ಅವಧಿಯನ್ನು ತಲುಪಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ಮುಖವನ್ನು ಸಂಗ್ರಹಿಸಲಾಗುವುದಿಲ್ಲ."</string>      <string name="face_error_canceled" msgid="283945501061931023">"ಮುಖದ ಕಾರ್ಯಚರಣೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ಮುಖ ದೃಢೀಕರಣವನ್ನು ಬಳಕೆದಾರರ ಮೂಲಕ ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ಹಲವು ಪ್ರಯತ್ನ. ಮುಖದ ದೃಢೀಕರಣ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index abed24c1070d..6223dab94da1 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"인식할 수 없음"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"지문이 인증됨"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"얼굴이 인증되었습니다"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"얼굴이 인증되었습니다. 확인을 누르세요"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"지문 인식 하드웨어를 사용할 수 없습니다."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"얼굴 인식 시간이 초과되었습니다. 다시 시도하세요."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"얼굴을 저장할 수 없습니다."</string>      <string name="face_error_canceled" msgid="283945501061931023">"얼굴 인식 작업이 취소되었습니다."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"사용자가 얼굴 인증을 취소했습니다."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"시도 횟수가 너무 많아 얼굴 인증이 사용 중지되었습니다."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"다시 시도해 보세요."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index fb8a81656499..f49746f756fa 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Таанылган жок"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Манжа изинин аныктыгы текшерилди"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Жүздүн аныктыгы текшерилди"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Жүздүн аныктыгы текшерилди, эми \"Ырастоону\" басыңыз"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Манжа изинин аппараттык камсыздоосу жеткиликтүү эмес."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Манжа изин сактоо мүмкүн эмес. Учурдагы манжа изин алып салыңыз."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Манжа изин күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Жүздүн аныктыгын текшерүүнү күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Жүздү сактоо мүмкүн эмес."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Жүздүн аныктыгын текшерүү колдонуучу аркылуу жокко чыгарылды."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Өтө көп жолу аракет жасадыңыз. Кийинчерээк кайра аракет кылыңыз."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Өтө көп жолу аракет жасадыңыз. Жүздүн аныктыгын текшерүү сенсору өчүрүлдү."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Кайра аракет кылыңыз."</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 8b6a052369fe..9fc60333c7ec 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ບໍ່ຮັບຮູ້"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ, ກະລຸນາກົດຢືນຢັນ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ບໍ່ມີຮາດແວລາຍນີ້ວມືໃຫ້ຢູ່."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ບໍ່ສາມາດເກັບຮັກສາລາຍນີ້ວມືໄວ້ໄດ້. ກະລຸນາເອົາລາຍນີ້ວມືທີ່ມີຢູ່ອອກໄປ."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ເວລາລາຍນີ້ວມືບໍ່ເຂົ້າເຖິງໄດ້. ລອງໃໝ່ອີກ."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ໝົດເວລາກວດໃບໜ້າແລ້ວ. ກະລຸນາລອງອີກຄັ້ງ."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ບໍ່ສາມາດເກັບຮັກສາໃບໜ້າໄວ້ໄດ້."</string>      <string name="face_error_canceled" msgid="283945501061931023">"ຍົກເລີກການດຳເນີນການກັບໃບໜ້າແລ້ວ."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ຜູ້ໃຊ້ຍົກເລີກການພິສູດຢືນຢັນໃບໜ້າແລ້ວ."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ປິດນຳໃຊ້ການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າແລ້ວ."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ລອງອີກຄັ້ງ."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 7fc1c9893539..d6869c108264 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Neatpažinta"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Kontrolinis kodas autentifikuotas"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Veidas autentifikuotas"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Veidas autentifikuotas, paspauskite patvirtinimo mygtuką"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Kontrolinio kodo aparatinė įranga nepasiekiama."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Negalima išsaugoti kontrolinio kodo. Pašalinkite esamą kontrolinį kodą."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Baigėsi kontrolinio kodo nustatymo skirtasis laikas. Bandykite dar kartą."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Baigėsi veido atpaž. skirt. laik. Band. dar kartą."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nepavyko išsaugoti veido duomenų."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Veido atpažinimo operacija atšaukta."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Veido autentifikavimą atšaukė naudotojas."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Per daug bandymų. Vėliau bandykite dar kartą."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Per daug bandymų. Veido autentifik. išjungtas."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Bandykite dar kartą."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 60a32de5d585..156a1a9adbf6 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Dati nav atpazīti"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Pirksta nospiedums tika autentificēts."</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Seja autentificēta"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Seja ir autentificēta. Nospiediet pogu Apstiprināt."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Nospieduma aparatūra nav pieejama."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Pirkstu nospiedumu nevar saglabāt. Lūdzu, noņemiet esošu pirksta nospiedumu."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Pirkstu nospiedumu nolasīšanas aparatūras noildze. Mēģiniet vēlreiz."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Sejas datu nolasīšanas noildze. Mēģiniet vēlreiz."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Sejas datus nevar saglabāt."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Darbība ar sejas datiem atcelta."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Lietotājs atcēla sejas autentificēšanu."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Par daudz mēģinājumu. Sejas atpazīšana atspējota."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Mēģiniet vēlreiz."</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 4ae6f31b4c4d..8bca75e0b764 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Непознат"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатокот е проверен"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицето е проверено"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицето е проверено, притиснете го копчето „Потврди“"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отпечаток од прст не е достапен."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатокот не може да се складира. Отстранете го постоечкиот отпечаток."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Се достигна времето на истекување на отпечатокот. Обидете се повторно."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Истече времето за проверка на лице. Повторен обид."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да се чува."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Операцијата со лице се откажа."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Проверката на лицето е откажана од корисникот."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Премногу обиди. Обидете се повторно подоцна."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Премногу обиди. Проверката на лице е оневозможена."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Обидете се повторно."</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 2cd83cc95ba4..1efdc7274cd5 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു, സ്ഥിരീകരിക്കുക അമർത്തുക"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ഫിംഗർപ്രിന്റ് ഹാർഡ്വെയർ ലഭ്യമല്ല."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"വിരലടയാളം സംഭരിക്കാനാവില്ല. നിലവിലുള്ള വിരലടയാളം നീക്കംചെയ്യുക."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"വിരലടയാളം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"മുഖം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"മുഖം സൂക്ഷിക്കാനാവില്ല."</string>      <string name="face_error_canceled" msgid="283945501061931023">"മുഖത്തിന്റെ പ്രവർത്തനം റദ്ദാക്കി."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"മുഖം പരിശോധിച്ചുറപ്പിക്കൽ ഉപയോക്താവ് റദ്ദാക്കി."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"നിരവധി തവണ ശ്രമിച്ചു. മുഖം തിരിച്ചറിയൽ പ്രവർത്തനരഹിതമാക്കി."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"വീണ്ടും ശ്രമിക്കുക."</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 35936eec055a..86ae178d49c3 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Таниагүй"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Хурууны хээг нотолсон"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Царайг баталгаажууллаа"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Царайг баталгаажууллаа. Баталгаажуулах товчлуурыг дарна уу"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хурууны хээний тоног төхөөрөмж бэлэн бус байна."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Хурууны хээг хадгалах боломжгүй байна. Одоо байгаа хурууны хээг арилгана уу."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Хурууны хээ оруулах хугацаа өнгөрсөн байна. Дахин оруулна уу."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Царай таниулах хугацаа дууслаа. Дахин оролдоно уу."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Царайг хадгалах боломжгүй байна."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Царайны үйл ажиллагааг цуцаллаа."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Хэрэглэгч царайгаар баталгаажуулахыг цуцалсан байна."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Хэт олон удаа оролдлоо. Царай танилтыг идэвхгүй болголоо."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Дахин оролдоно уу."</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index ec96ec17baa4..70ed01221dc5 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"चेहरा ऑथेंटिकेशन केलेला आहे"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म दाबा"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फिंगरप्रिंट हार्डवेअर उपलब्ध नाही."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"फिंगरप्रिंट स्टोअर केले जाऊ शकत नाही. कृपया विद्यमान फिंगरप्रिंट काढा."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फिंगरप्रिंट टाइमआउट झाले. पुन्हा प्रयत्न करा."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"चेहरा टाइमआउट झाला. पुन्हा प्रयत्न करा."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"चेहरा स्टोअर केला जाऊ शकत नाही."</string>      <string name="face_error_canceled" msgid="283945501061931023">"चेहरा ऑपरेशन रद्द केले गेले."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"वापरकर्त्याने चेहरा ऑथेंटिकेशन रद्द केले."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"खूप जास्त प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"खूप जास्त प्रयत्न केले. चेहरा ऑथेंटिकेशन बंद केले गेले."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"पुन्हा प्रयत्न करा."</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 7de8dc110f46..208fed6d89ac 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Cap jari disahkan"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Wajah disahkan"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Wajah disahkan, sila tekan sahkan"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Perkakasan cap jari tidak tersedia."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Cap jari tidak dapat disimpan. Sila alih keluar cap jari sedia ada."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tamat masa cap jari dicapai. Cuba lagi."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tamat masa wajah dicapai. Cuba lagi."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Pengendalian wajah dibatalkan."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Pengesahan wajah dibatalkan oleh pengguna."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu banyak percubaan. Pengesahan wajah dilumpuhkan."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Cuba lagi."</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 9f107f88362b..71dd4b65aeee 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"မသိပါ"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ၊ အတည်ပြုရန်ကို နှိပ်ပါ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"လက်ဗွေရာ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"လက်ဗွေရာ သိုလှောင်၍မရပါ။ ကျေးဇူးပြု၍ ရှိပြီးလက်ဗွေရာအား ဖယ်ရှားပါ။"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"လက်ဗွေရာအချိန်ကုန် သွားပါသည်။ ထပ်မံကြိုးစားပါ။"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"မျက်နှာ သက်တမ်းကုန်သွားပါပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"မျက်နှာကို သိမ်း၍မရပါ။"</string>      <string name="face_error_canceled" msgid="283945501061931023">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"အသုံးပြုသူက မျက်နှာအထောက်အထားစိစစ်မှု မလုပ်တော့ပါ။"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ ပိတ်လိုက်ပါပြီ။"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ထပ်စမ်းကြည့်ပါ။"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d315acaa8bfe..28e7d334e0cf 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke gjenkjent"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrykket er godkjent"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansiktet er autentisert"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansiktet er autentisert. Trykk på Bekreft"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maskinvare for fingeravtrykk er ikke tilgjengelig."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrykket kan ikke lagres. Fjern et eksisterende fingeravtrykk."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsavbrudd for fingeravtrykk er nådd. Prøv på nytt."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tidsavbrudd for ansikt er nådd. Prøv igjen."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Ansiktet kan ikke lagres."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Ansikt-operasjonen ble avbrutt."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ansiktsautentiseringen ble avbrutt av brukeren."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"For mange forsøk. Prøv igjen senere."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøk. Ansiktsautentisering er slått av."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igjen."</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index c67a871e08a1..875f87deb12e 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"अनुहार प्रमाणीकरण गरियो"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"अनुहार प्रमाणीकरण गरियो, कृपया पुष्टि गर्नुहोस् थिच्नुहोस्"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"औँठाछाप हार्डवेयर उपलब्ध छैन।"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"औँठाछाप भण्डारण गर्न सकिँदैन। कृपया अवस्थित औठाछाप हटाउनुहोस्।"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"अनुहारको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"अनुहार भण्डारण गर्न सकिँदैन।"</string>      <string name="face_error_canceled" msgid="283945501061931023">"अनुहार पहिचान रद्द गरियो।"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"प्रयोगकर्ताले अनुहार प्रमाणीकरण रद्द गर्नु भयो।"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"धेरैपटक प्रयासहरू भए। पछि फेरि प्रयास गर्नुहोस्।"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"अत्यधिक धेरैपटक गलत प्रयासहरू भए। अनुहार प्रमाणिकरणलाई असक्षम पारियो।"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"फेरि प्रयास गर्नुहोस्।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 345d9d49d60e..b95ba194a326 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Niet herkend"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk geverifieerd"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gezicht geverifieerd"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gezicht geverifieerd. Druk op Bevestigen."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware voor vingerafdruk niet beschikbaar."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan niet worden opgeslagen. Verwijder een bestaande vingerafdruk."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Time-out bereikt voor vingerafdruk. Probeer het opnieuw."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Time-out voor gezicht bereikt. Probeer opnieuw."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Gezicht kan niet worden opgeslagen."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Bewerking voor gezichtsherkenning geannuleerd."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gezichtsverificatie geannuleerd door gebruiker."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogingen. Probeer het later opnieuw."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogingen. Gezichtsherkenning inactief."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer het opnieuw."</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 3e4260f4ca0f..9d3fa8e06765 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରମାଣୀକୃତ ହେଲା"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି, ଦୟାକରି ସୁନିଶ୍ଚିତ ଦବାନ୍ତୁ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ। ଦୟାକରି ପୂର୍ବରୁ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ବାହାର କରିଦିଅନ୍ତୁ।"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ଆଙ୍ଗୁଠି ଚିହ୍ନର ସମୟ ଶେଷ ହେଲା । ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ଫେସ୍ର ସମୟସୀମା ସରିଗଲା। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ଫେସ୍ ମେମୋରୀରେ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ।"</string>      <string name="face_error_canceled" msgid="283945501061931023">"ଫେସ୍ର ଅପରେଶନ୍ କ୍ୟାନ୍ସଲ୍ ହୋଇଗଲା"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ଉପଯୋଗକର୍ତ୍ତା ମୁହଁ ଚିହ୍ନଟକରଣ ବାତିଲ୍ କରିଛନ୍ତି।"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ବାରମ୍ବାର ଚେଷ୍ଟା। ପରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ବାରମ୍ବାର ଚେଷ୍ଟା। ଫେସ୍ ପ୍ରମାଣୀକରଣ ଅକ୍ଷମ କରାଗଲା।"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index bdcf2fec85a1..6e615a88119b 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ, ਕਿਰਪਾ ਕਰਕੇ \'ਪੁਸ਼ਟੀ ਕਰੋ\' ਦਬਾਓ"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਮੌਜੂਦਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਟਾਓ।"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਗਿਆ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ਚਿਹਰਾ ਪਛਾਣਨ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ਚਿਹਰੇ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>      <string name="face_error_canceled" msgid="283945501061931023">"ਚਿਹਰਾ ਪਛਾਣਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਰੱਦ ਕੀਤੀ ਗਈ।"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ ਨੂੰ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਰਨ ਬੰਦ ਹੈ।"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 3e08d500520a..81a869addd25 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie rozpoznano"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Uwierzytelniono odciskiem palca"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Twarz rozpoznana"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Twarz rozpoznana, kliknij Potwierdź"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Czytnik linii papilarnych nie jest dostępny."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nie można zapisać odcisku palca. Usuń istniejący odcisk palca."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Osiągnięto limit czasu odczytu linii papilarnych. Spróbuj ponownie."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Upłynął limit czasu analizy twarzy. Spróbuj ponownie."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Nie można zapisać informacji o twarzy."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Analiza twarzy została anulowana."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Użytkownik anulował uwierzytelnianie twarzą."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Zbyt wiele prób. Spróbuj ponownie później."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zbyt wiele prób. Wyłączono uwierzytelnianie za pomocą twarzy."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Spróbuj ponownie."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index d604aab7b9a1..5ac7c2e5db5d 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado, pressione \"Confirmar\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo usuário."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index cde63d54d2b7..52f067fb1d09 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -423,11 +423,11 @@      <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas definições de áudio"</string>      <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que a aplicação modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>      <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string> -    <string name="permdesc_recordAudio" msgid="4245930455135321433">"Esta aplicação pode gravar áudio através do microfone a qualquer momento."</string> +    <string name="permdesc_recordAudio" msgid="4245930455135321433">"Esta aplicação pode gravar áudio através do microfone em qualquer altura."</string>      <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o SIM"</string>      <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que a aplicação envie comandos para o SIM. Esta ação é muito perigosa."</string>      <string name="permlab_camera" msgid="3616391919559751192">"tirar fotos e vídeos"</string> -    <string name="permdesc_camera" msgid="5392231870049240670">"Esta aplicação pode tirar fotos e gravar vídeos através da câmara a qualquer momento."</string> +    <string name="permdesc_camera" msgid="5392231870049240670">"Esta aplicação pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>      <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>      <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>      <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string> @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido."</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"A impressão digital foi autenticada."</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado."</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado. Prima Confirmar."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não é possível armazenar a impressão digital. Remova uma impressão digital existente."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Foi atingido o limite de tempo da impressão digital. Tente novamente."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Limite de tempo de rosto atingido. Tente novamente."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar o rosto."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operação de rosto cancelada."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo utilizador."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Demasiadas tentativas. Tente novamente mais tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiadas tentativas. Autenticação facial desativada."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index d604aab7b9a1..5ac7c2e5db5d 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado, pressione \"Confirmar\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo usuário."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index add43b849234..0c945f71cab1 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nu este recunoscut"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Amprentă autentificată"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Chip autentificat"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Chip autentificat, apăsați Confirmați"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware-ul pentru amprentă nu este disponibil."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Amprenta nu poate fi stocată. Eliminați o amprentă existentă."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timpul pentru amprentare a expirat. Încercați din nou."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Timpul pentru reunoaștere facială a expirat. Încercați din nou."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Chipul nu poate fi stocat."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operațiunea privind chipul a fost anulată."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentificarea chipului anulată de utilizator."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Prea multe încercări. Reîncercați mai târziu."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Prea multe încercări. Autentificarea facială este dezactivată."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Încercați din nou."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 3a4ed8242875..fd70e9c7a4ae 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распознано"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечаток пальца проверен"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицо распознано"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицо распознано, нажмите кнопку \"Подтвердить\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Сканер недоступен"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Чтобы сохранить новый отпечаток, удалите существующий."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Превышено время ожидания. Повторите попытку."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Невозможно сохранить распознанное лицо"</string>      <string name="face_error_canceled" msgid="283945501061931023">"Распознавание отменено"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Распознавание лица отменено пользователем."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Слишком много попыток. Повторите позже."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Слишком много попыток. Сканер отключен."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Попробуйте ещё раз"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 17ead66d2c81..3bd8ceb5b0f9 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"මුහුණ සත්යාපනය කරන ලදී"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"මුහුණ සත්යාපනය කරන ලදී, කරුණාකර තහවුරු කරන්න ඔබන්න"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ඇඟිලි සලකුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"මුහුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"මුහුණ ගබඩා කළ නොහැක."</string>      <string name="face_error_canceled" msgid="283945501061931023">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"පරිශීලකයා විසින් මුහුණ සත්යාපනය අවලංගු කරන ලදී."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"උත්සාහයන් ඉතා වැඩි ගණනකි. පසුව නැවත උත්සාහ කරන්න."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණු සත්යාපනය අබල කරන ලදී."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"නැවත උත්සාහ කරන්න."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index cb44b7422e3b..c0981cefa32d 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznané"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Odtlačok bol overený"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Tvár bola overená"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Tvár bola overená, stlačte tlačidlo potvrdenia"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardvér na snímanie odtlačku prsta nie je k dispozícii"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Odtlačok prsta nie je možné uložiť. Odstráňte existujúci odtlačok."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit rozpoznania odtlačku vypršal. Skúste to znova."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Limit rozpoznania tváre vypršal. Skúste to znova."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Tvár sa nedá uchovať."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Operácia týkajúca sa tváre bola zrušená"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Overenie tváre bolo zrušené používateľom."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Príliš veľa pokusov. Skúste to znova neskôr."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Príliš veľa pokusov. Overenie tváre je zakázané."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Skúste to znova."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 039bbaa47b3e..261e6ed61bfc 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Ni prepoznano"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Pristnost prstnega odtisa je preverjena"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Pristnost obraza je potrjena"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Pristnost obraza je preverjena. Pritisnite gumb »Potrdi«."</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Strojna oprema za prstne odtise ni na voljo."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Prstnega odtisa ni mogoče shraniti. Odstranite obstoječi prstni odtis."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Dosežena časovna omejitev za prstni odtis. Poskusite znova."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Dosežena časovna omejitev za obraz. Poskusite znova."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Obraza ni mogoče shraniti."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Dejanje z obrazom je bilo preklicano."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Preverjanje pristnosti obraza preklical uporabnik"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Preveč poskusov. Poskusite znova pozneje."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Preveč poskusov. Preverjanje pristnosti obraza je onemogočeno."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Poskusite znova."</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index ee0960bb10b0..4b6cb099e4b6 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Nuk njihet"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Gjurma e gishtit u vërtetua"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Fytyra u vërtetua"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Fytyra u vërtetua, shtyp \"Konfirmo\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardueri i gjurmës së gishtit nuk mundësohet."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Gjurma e gishtit nuk mund të ruhet. Hiq një gjurmë gishti ekzistuese."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Koha e veprimit për gjurmën e gishtit skadoi. Provo përsëri."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Mbaroi afati për fytyrën. Provo sërish."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Fytyra nuk mund të ruhet."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Veprimi me fytyrën u anulua."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Vërtetimi me fytyrë u anulua nga përdoruesi."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Shumë përpjekje. Provo sërish më vonë."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Shumë përpjekje. Vërtetimi për fytyrën joaktiv."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Provo sërish."</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 6ff3a7837e12..449fdfc89448 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -531,10 +531,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Није препознато"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отисак прста је потврђен"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лице је потврђено"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лице је потврђено. Притисните Потврди"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string> @@ -571,8 +569,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Истекло је време за проверу лица. Пробајте поново."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Није могуће сачувати лице."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Обрада лица је отказана."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Корисник је отказао потврду лица."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Превише покушаја. Пробајте поново касније."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Више покушаја. Потврда идентитета је онемогућена."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Пробајте поново."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 20969d3daf2e..9f46514ba1f0 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Identifierades inte"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrycket har autentiserats"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansiktet har autentiserats"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansiktet har autentiserats. Tryck på Bekräfta"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Det finns ingen maskinvara för fingeravtryck."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrycket kan inte lagras. Ta bort ett befintligt fingeravtryck."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsgränsen för fingeravtrycket har uppnåtts. Försök igen."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Tidsgränsen för ansikte har nåtts. Försök igen."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Det gick inte att lagra ansiktet."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Ansiktsåtgärden har avbrutits."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentiseringen av ansiktet avbröts av användaren."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Du har gjort för många försök. Försök igen senare."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"För många försök. Ansiktsautentisering inaktiverad"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Försök igen."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index ce81bc7c3adb..b0858dc0d4c8 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -130,9 +130,9 @@    </string-array>      <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->      <skip /> -    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>Kupiga simu Kupitia Wi-Fi"</string> +    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Kupiga Simu Kupitia Wi-Fi ya <xliff:g id="SPN">%s</xliff:g>"</string>      <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Simu ya WLAN"</string> -    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> Simu ya WLAN"</string> +    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Simu ya WLAN ya <xliff:g id="SPN">%s</xliff:g>"</string>      <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ya <xliff:g id="SPN">%s</xliff:g>"</string>      <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Kupiga Simu kupitia WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>      <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi ya <xliff:g id="SPN">%s</xliff:g>"</string> @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Hayatambuliki"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Imethibitisha alama ya kidole"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Uso umethibitishwa"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Uso umethibitishwa, tafadhali bonyeza thibitisha"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maunzi ya kitambulisho hayapatikani."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Kitambulisho hakiwezi kuhifadhiwa. Tafadhali ondoa kitambulisho kilichopo."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Muda wa kitambulisho umekwisha. Jaribu tena."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Muda wa kutambua uso umeisha. Jaribu tena."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Huwezi kuhifadhi uso."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Utendaji wa kitambulisho umeghairiwa."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Uthibitishaji wa uso umeghairiwa na mtumiaji."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Umejaribu mara nyingi mno. Jaribu tena baadaye."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Umejaribu mara nyingi mno. Kitambuzi cha uso kimezimwa."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Jaribu tena."</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 9683e4cb21ce..b84d68e7cc02 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"அடையாளங்காணபடவில்லை"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"கைரேகை அங்கீகரிக்கப்பட்டது"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"முகம் அங்கீகரிக்கப்பட்டது"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"முகம் அங்கீகரிக்கப்பட்டது. ’உறுதிப்படுத்துக’ என்பதை அழுத்துக"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"கைரேகை வன்பொருள் இல்லை."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"கைரேகையைச் சேமிக்க முடியவில்லை. ஏற்கனவே உள்ள கைரேகையை அகற்றவும்."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"கைரேகைக்கான நேரம் முடிந்தது. மீண்டும் முயலவும்."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"முகப் பதிவிற்கான நேரம் முடிந்தது. மீண்டும் முயல்க."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"முகத்தைச் சேமிக்க இயலாது."</string>      <string name="face_error_canceled" msgid="283945501061931023">"முக அங்கீகாரச் செயல்பாடு ரத்துசெய்யப்பட்டது."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"பயனர், முக அங்கீகாரத்தை ரத்துசெய்தார்."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"பலமுறை முயன்றுவிட்டீர்கள். பிறகு முயலவும்."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"பலமுறை தோல்வி. முக அங்கீகாரம் முடக்கப்பட்டது."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"மீண்டும் முயலவும்."</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 975772061516..a5430b684b6c 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"వేలిముద్ర ప్రమాణీకరించబడింది"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ముఖం ప్రమాణీకరించబడింది"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ముఖం ప్రమాణీకరించబడింది, దయచేసి ధృవీకరించును నొక్కండి"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"వేలిముద్ర హార్డ్వేర్ అందుబాటులో లేదు."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"వేలిముద్రను నిల్వ చేయడం సాధ్యపడదు. దయచేసి ఇప్పటికే ఉన్న వేలిముద్రను తీసివేయండి."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"ముఖ గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"ముఖం నిల్వ చేయబడదు."</string>      <string name="face_error_canceled" msgid="283945501061931023">"ముఖ కార్యకలాపం రద్దయింది."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"వినియోగదారు ద్వారా ముఖ ప్రమాణీకరణ రద్దు చేయబడింది."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. ముఖ ప్రమాణీకరణ నిలిపివేయబడింది."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"మళ్లీ ప్రయత్నించండి."</string> diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml index 0712cbcfc024..48b59c70a61e 100644 --- a/core/res/res/values-television/themes.xml +++ b/core/res/res/values-television/themes.xml @@ -15,7 +15,6 @@  -->  <resources>      <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" /> -    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />      <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />      <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />      <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" /> diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml index b92c44e9f444..fdd06242c1e0 100644 --- a/core/res/res/values-television/themes_device_defaults.xml +++ b/core/res/res/values-television/themes_device_defaults.xml @@ -15,6 +15,7 @@  -->  <resources>      <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" /> +    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />      <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />      <!-- TODO(b/116457731): remove colorBackground from colors_material.xml if not used anymore --> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 89202ca06866..0b7e0310fe26 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"ไม่รู้จัก"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ตรวจสอบสิทธิ์ใบหน้าแล้ว โปรดกดยืนยัน"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ฮาร์ดแวร์ลายนิ้วมือไม่พร้อมใช้งาน"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ไม่สามารถเก็บลายนิ้วมือได้ โปรดนำลายนิ้วมือที่มีอยู่ออก"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"หมดเวลาใช้ลายนิ้วมือแล้ว โปรดลองอีกครั้ง"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"หมดเวลาใช้ใบหน้าแล้ว โปรดลองอีกครั้ง"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"จัดเก็บข้อมูลใบหน้าไม่ได้"</string>      <string name="face_error_canceled" msgid="283945501061931023">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"ผู้ใช้ยกเลิกการตรวจสอบสิทธิ์ใบหน้า"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ดำเนินการหลายครั้งเกินไป ปิดใช้การตรวจสอบสิทธิ์ด้วยใบหน้าแล้ว"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"ลองอีกครั้ง"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 983b53f81450..e21f59cad183 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Hindi nakilala"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Na-authenticate ang fingerprint"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Na-authenticate ang mukha"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Na-authenticate ang mukha, pakipindot ang kumpirmahin"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hindi available ang hardware na ginagamitan ng fingerprint."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Hindi maiimbak ang fingerprint. Mangyaring mag-alis ng umiiral nang fingerprint."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Nag-time out ang fingerprint. Subukang muli."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Nag-time out ang mukha. Subukang muli."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Hindi ma-store ang mukha."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Nakansela ang operation kaugnay ng mukha."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Kinansela ng user ang pag-authenticate ng mukha."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Masyadong maraming pagsubok. Subukang muli mamaya."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Sobrang pagsubok. Bawal na: facial authentication."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Subukang muli."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 031527623c57..912db2001851 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Parmak izi kimlik doğrulaması yapıldı"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Yüz kimliği doğrulandı"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yüz kimliği doğrulandı, lütfen onayla\'ya basın"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Parmak izi donanımı kullanılamıyor."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Parmak izi depolanamıyor. Lütfen mevcut parmak izlerinden birini kaldırın."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Parmak izi için zaman aşımı oluştu. Tekrar deneyin."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Yüz için zaman aşımı oluştu. Tekrar deneyin."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Yüz kaydedilemiyor."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Yüz işlemi iptal edildi."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Yüz kimlik doğrulama işlemini kullanıcı iptal etti."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Çok fazla deneme yapıldı. Yüz kimlik doğrulaması devre dışı bırakıldı."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Tekrar deneyin."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 88e2475ffe6c..f84e3e2e67f6 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -534,10 +534,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Не розпізнано"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Відбиток автентифіковано"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Обличчя автентифіковано"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Обличчя автентифіковано. Натисніть \"Підтвердити\""</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратне забезпечення для сканування відбитка недоступне."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Не вдалося зберегти відбиток. Видаліть наявний відбиток."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час очікування відбитка минув. Повторіть спробу."</string> @@ -574,8 +572,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Час очікування обличчя минув. Повторіть спробу."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Не вдається зберегти обличчя."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Дію з обличчям скасовано."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Користувач скасував автентифікацію облич."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Забагато спроб. Повторіть пізніше."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Забагато спроб. Автентифікацію обличчя вимкнено."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Повторіть спробу."</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 6e98ebbd275d..dc801cd96d78 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"فنگر پرنٹ کی تصدیق ہو گئی"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"چہرے کی تصدیق ہو گئی"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"چہرے کی تصدیق ہو گئی، براہ کرم \'تصدیق کریں\' کو دبائيں"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"فنگر پرنٹ ہارڈ ویئر دستیاب نہیں ہے۔"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"چہرہ پہچانے کی میعاد ختم ہو گئی۔ دوبارہ کوشش کریں۔"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"چہرے کو اسٹور نہیں کیا جا سکتا۔"</string>      <string name="face_error_canceled" msgid="283945501061931023">"چہرے پر ہونے والی کارروائی منسوخ ہو گئی۔"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"صارف نے چہرے کی تصدیق کو مسترد کر دیا۔"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"کافی زیادہ کوششیں کی گئیں۔ دوبارہ کوشش کریں۔"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"کافی زیادہ کوششیں کی گئیں۔ چہرے کی توثیق منسوخ ہو گئی۔"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"دوبارہ کوشش کریں۔"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 15671d18056f..e51b8103f7df 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Aniqlanmadi"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmoq izi tekshirildi"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Yuzingiz aniqlandi"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yuzingiz aniqlandi, tasdiqlash uchun bosing"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi skaneri ish holatida emas."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmoq izini saqlab bo‘lmadi. Mavjud barmoq izlaridan birini o‘chirib tashlang."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmoq izini aniqlash vaqti tugab qoldi. Qayta urinib ko‘ring."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Yuzni aniqlash vaqti tugadi. Qaytadan urining."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Aniqlangan yuz saqlanmadi."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Yuzni aniqlash bekor qilindi."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Yuz tekshiruvi bekor qilindi."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Juda ko‘p urinildi. Keyinroq qaytadan urining."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Juda ko‘p urinildi. Skaner faolsizlantirildi."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Qaytadan urining."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 00ebbbcd342e..4d8a20b5dade 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Đã xác thực vân tay"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Đã xác thực khuôn mặt"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Đã xác thực khuôn mặt, vui lòng nhấn để xác nhận"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Phần cứng vân tay không khả dụng."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Không thể lưu vân tay. Vui lòng xóa vân tay hiện có."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Đã hết thời gian chờ vân tay. Hãy thử lại."</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Đã hết thời gian chờ khuôn mặt. Hãy thử lại."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Không thể lưu khuôn mặt."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Đã hủy thao tác dùng khuôn mặt."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Người dùng đã hủy thao tác xác thực khuôn mặt."</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Bạn đã thử quá nhiều lần. Hãy thử lại sau."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Đã thử quá nhiều lần. Đã tắt xác thực khuôn mặt."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Hãy thử lại."</string> diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml deleted file mode 100644 index 1be47baf4e7f..000000000000 --- a/core/res/res/values-watch/themes.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 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. ---> -<resources> -    <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. --> -    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert"> -        <item name="windowContentTransitions">false</item> -        <item name="windowActivityTransitions">false</item> -        <item name="windowCloseOnTouchOutside">false</item> -    </style> -</resources> diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml index a7736e7c3e82..bfba312da016 100644 --- a/core/res/res/values-watch/themes_device_defaults.xml +++ b/core/res/res/values-watch/themes_device_defaults.xml @@ -422,6 +422,13 @@ a similar way.          <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>      </style> +    <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. --> +    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert"> +        <item name="windowContentTransitions">false</item> +        <item name="windowActivityTransitions">false</item> +        <item name="windowCloseOnTouchOutside">false</item> +    </style> +      <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">          <!-- Color palette Dark -->          <item name="colorPrimary">@color/primary_device_default_dark</item> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index e60afa731f9a..609f9bcfb71d 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"无法识别"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"已验证指纹"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"面孔已验证"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"面孔已验证,请按确认按钮"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指纹硬件无法使用。"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"无法存储指纹。请移除一个现有的指纹。"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"面孔处理操作超时,请重试。"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"无法存储面孔。"</string>      <string name="face_error_canceled" msgid="283945501061931023">"面孔处理操作已取消。"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"用户已取消面孔验证。"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"尝试次数过多,请稍后重试。"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"尝试次数过多,系统已停用人脸身份验证功能。"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"请重试。"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index cb93c61df88f..2e3c7d75857a 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"未能識別"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"驗證咗指紋"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"面孔已經驗證"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"面孔已經驗證,請㩒一下 [確認]"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"無法使用指紋軟件。"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋無法儲存。請移除現有指紋。"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋已逾時。請再試一次。"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"臉孔操作已逾時,請再試一次。"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>      <string name="face_error_canceled" msgid="283945501061931023">"臉孔操作已取消。"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"使用者已取消臉孔驗證。"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證已停用。"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 9c3d75ba68e5..9149f47e86d6 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"無法辨識"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋驗證成功"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"臉孔驗證成功"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"臉孔驗證成功,請按下 [確認] 按鈕"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋硬體無法使用。"</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"無法儲存指紋,請先移除現有指紋。"</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"臉孔處理作業逾時,請再試一次。"</string>      <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>      <string name="face_error_canceled" msgid="283945501061931023">"臉孔處理作業已取消。"</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"使用者已取消臉孔驗證。"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證功能已停用。"</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 07c05aac0836..75709ca90174 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -528,10 +528,8 @@    </string-array>      <string name="biometric_not_recognized" msgid="5770511773560736082">"Akwaziwa"</string>      <string name="fingerprint_authenticated" msgid="5309333983002526448">"Isingxivizo somunwe sigunyaziwe"</string> -    <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) --> -    <skip /> -    <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) --> -    <skip /> +    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ubuso bufakazelwe ubuqiniso"</string> +    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ukuqinisekiswa kobuso, sicela ucindezele okuthi qinisekisa"</string>      <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Izingxenyekazi zekhompuyutha zezingxivizo zeminwe azitholakali."</string>      <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Izigxivizo zeminwe azikwazi ukugcinwa. Sicela ususe izigxivizo zeminwe ezikhona."</string>      <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Kufinyelelwe isikhathi sokuvala sezigxivizo zeminwe. Zama futhi"</string> @@ -568,8 +566,7 @@      <string name="face_error_timeout" msgid="4014326147867150054">"Kufinyelelwe kusikhathi sokuvala sobuso. Zama futhi."</string>      <string name="face_error_no_space" msgid="8224993703466381314">"Ubuso abukwazi ukugcinwa."</string>      <string name="face_error_canceled" msgid="283945501061931023">"Umsebenzi wobuso ukhanselwe."</string> -    <!-- no translation found for face_error_user_canceled (8943921120862164539) --> -    <skip /> +    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ukufakazela ubuqiniso kobuso kukhanselwe umsebenzisi"</string>      <string name="face_error_lockout" msgid="3407426963155388504">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>      <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Imizamo eminingi kakhulu. Ukufakazela ubuqiniso kobuso kukhutshaziwe."</string>      <string name="face_error_unable_to_process" msgid="238761109287767270">"Zama futhi."</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 65b88076abf0..e0db9463a091 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1425,7 +1425,7 @@               at {@link android.view.inputmethod.InputConnection#performEditorAction(int)               InputConnection.performEditorAction(int)}.               <p>Corresponds to -             {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_FULLSCREEN}. --> +             {@link android.view.inputmethod.EditorInfo#IME_FLAG_NAVIGATE_PREVIOUS}. -->          <flag name="flagNavigatePrevious" value="0x4000000" />          <!-- Used to specify that there is something               interesting that a forward navigation can focus on. This is like using diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 3c0e51ed4cdd..8ff29ba4614c 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1102,6 +1102,10 @@           <p>The default value of this attribute is <code>false</code>. -->      <attr name="isFeatureSplit" format="boolean" /> +    <!-- Flag to specify if this APK requires at least one split [either feature or +         resource] to be present in order to function. Default value is false. --> +    <attr name="isSplitRequired" format="boolean" /> +      <!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or           {@code <application>} tag. If specified on the {@code <application>}           tag these will be considered defaults for all activities in the @@ -1422,6 +1426,7 @@          <attr name="targetSandboxVersion" />          <attr name="compileSdkVersion" />          <attr name="compileSdkVersionCodename" /> +        <attr name="isSplitRequired" />      </declare-styleable>      <!-- The <code>application</code> tag describes application-level components diff --git a/core/res/res/values/colors_car.xml b/core/res/res/values/colors_car.xml index 6053728369e1..32671ac8f752 100644 --- a/core/res/res/values/colors_car.xml +++ b/core/res/res/values/colors_car.xml @@ -17,15 +17,271 @@   */  -->  <resources> -  <!-- car support colors from -  https://cs.corp.google.com/android/frameworks/support/car/res/values/colors.xml --> -  <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color> -  <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color> -  <color name="car_card_dark">@color/car_dark_blue_grey_700</color> -  <color name="car_body1_light">@color/car_grey_100</color> - -  <color name="car_grey_50">#fffafafa</color> -  <color name="car_grey_900">#ff212121</color> -  <color name="car_dark_blue_grey_700">#ff172026</color> -  <color name="car_grey_100">#fff5f5f5</color> +    <color name="car_background">@color/black</color> + +    <color name="car_colorPrimary">@color/car_grey_868</color> +    <color name="car_colorSecondary">@color/car_grey_900</color> +    <color name="car_colorPrimaryDark">@color/car_grey_958</color> + + +    <!-- Various colors for text sizes. "Light" and "dark" here refer to the lighter or darker +          shades. --> +    <color name="car_title_light">@color/car_grey_100</color> +    <color name="car_title_dark">@color/car_grey_900</color> +    <color name="car_title">@color/car_title_light</color> + +    <color name="car_title2_light">@color/car_grey_100</color> +    <color name="car_title2_dark">@color/car_grey_900</color> +    <color name="car_title2">@color/car_title2_light</color> + +    <color name="car_headline1_light">@color/car_grey_100</color> +    <color name="car_headline1_dark">@color/car_grey_800</color> +    <color name="car_headline1">@color/car_headline1_light</color> + +    <color name="car_headline2_light">@color/car_grey_100</color> +    <color name="car_headline2_dark">@color/car_grey_900</color> +    <color name="car_headline2">@color/car_headline2_light</color> + +    <color name="car_headline3_light">@android:color/white</color> +    <color name="car_headline3_dark">@color/car_grey_900</color> +    <color name="car_headline3">@color/car_headline3_light</color> + +    <color name="car_headline4_light">@android:color/white</color> +    <color name="car_headline4_dark">@android:color/black</color> +    <color name="car_headline4">@color/car_headline4_light</color> + +    <color name="car_body1_light">@color/car_grey_100</color> +    <color name="car_body1_dark">@color/car_grey_900</color> +    <color name="car_body1">@color/car_body1_light</color> + +    <color name="car_body2_light">@color/car_grey_300</color> +    <color name="car_body2_dark">@color/car_grey_700</color> +    <color name="car_body2">@color/car_body2_light</color> + +    <color name="car_body3_light">@android:color/white</color> +    <color name="car_body3_dark">@android:color/black</color> +    <color name="car_body3">@color/car_body3_light</color> + +    <color name="car_body4_light">@android:color/white</color> +    <color name="car_body4_dark">@android:color/black</color> +    <color name="car_body4">@color/car_body4_light</color> + +    <color name="car_action1_light">@color/car_grey_900</color> +    <color name="car_action1_dark">@color/car_grey_50</color> +    <color name="car_action1">@color/car_action1_light</color> + +    <!-- The tinting colors to create a light- and dark-colored icon respectively. --> +    <color name="car_tint_light">@color/car_grey_50</color> +    <color name="car_tint_dark">@color/car_grey_900</color> + +    <!-- The tinting color for an icon. This icon is assumed to be on a light background. --> +    <color name="car_tint">@color/car_tint_light</color> + +    <!-- An inverted tinting from car_tint. --> +    <color name="car_tint_inverse">@color/car_tint_dark</color> + +    <!-- The color of the divider. The color here is a lighter shade. --> +    <color name="car_list_divider_light">#1fffffff</color> + +    <!-- The color of the divider. The color here is a darker shade. --> +    <color name="car_list_divider_dark">#1f000000</color> + +    <!-- The color of the dividers in the list. This color is assumed to be on a light colored +         view. --> +    <color name="car_list_divider">@color/car_list_divider_light</color> + +    <!-- A light and dark colored card. --> +    <color name="car_card_light">@color/car_grey_50</color> +    <color name="car_card_dark">@color/car_dark_blue_grey_700</color> + +    <!-- The default color of a card in car UI. --> +    <color name="car_card">@color/car_card_dark</color> + +    <!-- The ripple colors. The "dark" and "light" designation here refers to the color of the +         ripple  itself. --> +    <color name="car_card_ripple_background_dark">#8F000000</color> +    <color name="car_card_ripple_background_light">#27ffffff</color> + +    <!-- The ripple color for a light colored card. --> +    <color name="car_card_ripple_background">@color/car_card_ripple_background_light</color> + +    <!-- The ripple color for a dark-colored card. This color is the opposite of +         car_card_ripple_background. --> +    <color name="car_card_ripple_background_inverse">@color/car_card_ripple_background_dark</color> + +    <!-- The top margin before the start of content in an application. --> +    <dimen name="app_header_height">96dp</dimen> + +    <!-- The lighter and darker color for the scrollbar thumb. --> +    <color name="car_scrollbar_thumb_light">#99ffffff</color> +    <color name="car_scrollbar_thumb_dark">#7f0b0f12</color> + +    <!-- The color of the scroll bar indicator in the PagedListView. This color is assumed to be on +         a light-colored background. --> +    <color name="car_scrollbar_thumb">@color/car_scrollbar_thumb_light</color> + +    <!-- The inverted color of the scroll bar indicator. This color is always the opposite of +         car_scrollbar_thumb. --> +    <color name="car_scrollbar_thumb_inverse">@color/car_scrollbar_thumb_dark</color> + +    <!-- The color of the seekbar track secondary progress in SeekbarListItem. --> +    <color name="car_seekbar_track_secondary_progress">@color/car_grey_500</color> + +    <!-- The lighter and darker color for the seekbar track background. --> +    <color name="car_seekbar_track_background_light">@color/car_grey_400</color> +    <color name="car_seekbar_track_background_dark">@color/car_grey_700</color> +    <!-- The color of the seekbar track background in SeekbarListItem. This color is assumed to be +         on a light-colored background. --> +    <color name="car_seekbar_track_background">@color/car_seekbar_track_background_dark</color> +    <!-- background is car_grey_868 with .9 alpha --> +    <color name="car_toast_background">#E6282a2d</color> + +    <!-- Misc colors --> +    <color name="car_highlight_light">@color/car_teal_700</color> +    <color name="car_highlight_dark">@color/car_teal_200</color> +    <color name="car_highlight">@color/car_highlight_dark</color> +    <color name="car_accent_light">@color/car_highlight_light</color> +    <color name="car_accent_dark">@color/car_highlight_dark</color> +    <color name="car_accent">@color/car_highlight_dark</color> + +    <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color> +    <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color> + +    <!-- Color palette for cars --> +    <color name="car_grey_958">#ff0e1013</color> +    <color name="car_grey_928">#ff17181b</color> +    <color name="car_grey_900">#ff202124</color> +    <color name="car_grey_868">#ff282a2d</color> +    <color name="car_grey_846">#ff2e3234</color> +    <color name="car_grey_800">#ff3c4043</color> +    <color name="car_grey_772">#ff464a4d</color> +    <color name="car_grey_746">#ff4d5256</color> +    <color name="car_grey_700">#ff5f6368</color> +    <color name="car_grey_600">#ff80868b</color> +    <color name="car_grey_500">#ff9aa0a6</color> +    <color name="car_grey_400">#ffbdc1c6</color> +    <color name="car_grey_300">#ffdadce0</color> +    <color name="car_grey_200">#ffe8eaed</color> +    <color name="car_grey_100">#fff1f3f4</color> +    <color name="car_grey_50">#fff8f9fa</color> + +    <color name="car_blue_900">#ff1d57a9</color> +    <color name="car_blue_800">#ff2065bb</color> +    <color name="car_blue_700">#ff2374ce</color> +    <color name="car_blue_600">#ff2581df</color> +    <color name="car_blue_500">#ff5195ea</color> +    <color name="car_blue_400">#ff6ba5ed</color> +    <color name="car_blue_300">#ff96bff2</color> +    <color name="car_blue_200">#ffb9d4f6</color> +    <color name="car_blue_100">#ffd9e6f9</color> +    <color name="car_blue_50">#ffebf1fc</color> + +    <color name="car_green_900">#ff136e39</color> +    <color name="car_green_800">#ff1b7e42</color> +    <color name="car_green_700">#ff218c48</color> +    <color name="car_green_600">#ff28994f</color> +    <color name="car_green_500">#ff41af6a</color> +    <color name="car_green_400">#ff5dba80</color> +    <color name="car_green_300">#ff8dcfa5</color> +    <color name="car_green_200">#ffb3dfc3</color> +    <color name="car_green_100">#ffd5ebdf</color> +    <color name="car_green_50">#ffe8f3ee</color> + +    <color name="car_red_900">#ffa81314</color> +    <color name="car_red_800">#ffb41b1a</color> +    <color name="car_red_700">#ffc22a2a</color> +    <color name="car_red_600">#ffd33b30</color> +    <color name="car_red_500">#ffe25142</color> +    <color name="car_red_400">#ffe66a5e</color> +    <color name="car_red_300">#ffed968d</color> +    <color name="car_red_200">#fff3b9b3</color> +    <color name="car_red_100">#fff7d8d9</color> +    <color name="car_red_50">#fffaebeb</color> + +    <color name="car_yellow_900">#ffdd860e</color> +    <color name="car_yellow_800">#ffe59810</color> +    <color name="car_yellow_700">#ffeda912</color> +    <color name="car_yellow_600">#fff3b713</color> +    <color name="car_yellow_500">#fff5c518</color> +    <color name="car_yellow_400">#fff6cd3a</color> +    <color name="car_yellow_300">#fff9dc74</color> +    <color name="car_yellow_200">#fffbe7a2</color> +    <color name="car_yellow_100">#fffcf0ce</color> +    <color name="car_yellow_50">#fffdf7e6</color> + +    <color name="car_orange_900">#ffb06000</color> +    <color name="car_orange_800">#ffc26401</color> +    <color name="car_orange_700">#ffd56e0c</color> +    <color name="car_orange_600">#ffe8710a</color> +    <color name="car_orange_500">#fffa7b17</color> +    <color name="car_orange_400">#fffa903e</color> +    <color name="car_orange_300">#fffcad70</color> +    <color name="car_orange_200">#fffdc69c</color> +    <color name="car_orange_100">#fffedfc8</color> +    <color name="car_orange_50">#fffeefe3</color> + +    <color name="car_pink_900">#ff9c166b</color> +    <color name="car_pink_800">#ffb80672</color> +    <color name="car_pink_700">#ffd01884</color> +    <color name="car_pink_600">#ffe52592</color> +    <color name="car_pink_500">#fff439a0</color> +    <color name="car_pink_400">#ffff63b8</color> +    <color name="car_pink_300">#ffff8bcb</color> +    <color name="car_pink_200">#fffba9d6</color> +    <color name="car_pink_100">#fffdcfe8</color> +    <color name="car_pink_50">#fffde7f3</color> + +    <color name="car_teal_900">#ff004d40</color> +    <color name="car_teal_800">#ff00695c</color> +    <color name="car_teal_700">#ff00796b</color> +    <color name="car_teal_600">#ff00897b</color> +    <color name="car_teal_500">#ff009688</color> +    <color name="car_teal_400">#ff26a69a</color> +    <color name="car_teal_300">#ff4db6ac</color> +    <color name="car_teal_200">#ff80cbc4</color> +    <color name="car_teal_100">#ffb2dfdb</color> +    <color name="car_teal_50">#ffe0f2f1</color> + +    <color name="car_purple_900">#ff681da8</color> +    <color name="car_purple_800">#ff7627bb</color> +    <color name="car_purple_700">#ff8430ce</color> +    <color name="car_purple_600">#ff9334e6</color> +    <color name="car_purple_500">#ffa142f4</color> +    <color name="car_purple_400">#ffaf5cf7</color> +    <color name="car_purple_300">#ffc58af9</color> +    <color name="car_purple_200">#ffd7aefb</color> +    <color name="car_purple_100">#ffe9d2fd</color> +    <color name="car_purple_50">#fff3e8fd</color> + +    <color name="car_cyan_900">#ff01877e</color> +    <color name="car_cyan_800">#ff099091</color> +    <color name="car_cyan_700">#ff12a4af</color> +    <color name="car_cyan_600">#ff12b5cb</color> +    <color name="car_cyan_500">#ff24c1e0</color> +    <color name="car_cyan_400">#ff4ecde6</color> +    <color name="car_cyan_300">#ff78d9ec</color> +    <color name="car_cyan_200">#ffa1e4f2</color> +    <color name="car_cyan_100">#ffcbf0f8</color> +    <color name="car_cyan_50">#ffe4f7fb</color> + + +    <color name="car_grey_1000">#cc000000</color> +    <color name="car_white_1000">#1effffff</color> +    <color name="car_blue_grey_800">#ff37474F</color> +    <color name="car_blue_grey_900">#ff263238</color> +    <color name="car_dark_blue_grey_600">#ff1d272d</color> +    <color name="car_dark_blue_grey_700">#ff172026</color> +    <color name="car_dark_blue_grey_800">#ff11181d</color> +    <color name="car_dark_blue_grey_900">#ff0c1013</color> +    <color name="car_dark_blue_grey_1000">#ff090c0f</color> +    <color name="car_light_blue_300">#ff4fc3f7</color> +    <color name="car_light_blue_500">#ff03A9F4</color> +    <color name="car_light_blue_600">#ff039be5</color> +    <color name="car_light_blue_700">#ff0288d1</color> +    <color name="car_light_blue_800">#ff0277bd</color> +    <color name="car_light_blue_900">#ff01579b</color> + + +    <color name="car_red_500a">#ffd50000</color> +    <color name="car_red_a700">#ffd50000</color>  </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1404383bc234..0daf5a76562d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2113,8 +2113,8 @@      <!-- Type of the long press sensor. Empty if long press is not supported. -->      <string name="config_dozeLongPressSensorType" translatable="false"></string> -    <!-- Type of the reach sensor. Empty if reach is not supported. --> -    <string name="config_dozeReachSensorType" translatable="false"></string> +    <!-- Type of sensor that wakes up the lock screen. Empty if not supported. --> +    <string name="config_dozeWakeLockScreenSensorType" translatable="false"></string>      <!-- Type of the wake up sensor. Empty if not supported. -->      <string name="config_dozeWakeScreenSensorType" translatable="false"></string> @@ -3541,4 +3541,13 @@      <!-- Brand value for attestation of misprovisioned device. -->      <string name="config_misprovisionedBrandValue" translatable="false"></string> + +    <!-- Pre-scale volume at volume step 1 for Absolute Volume --> +    <fraction name="config_prescaleAbsoluteVolume_index1">50%</fraction> + +    <!-- Pre-scale volume at volume step 2 for Absolute Volume --> +    <fraction name="config_prescaleAbsoluteVolume_index2">70%</fraction> + +    <!-- Pre-scale volume at volume step 3 for Absolute Volume --> +    <fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction>  </resources> diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index 7d14f868fefc..a0c02ede1890 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -16,12 +16,86 @@  */  -->  <resources> -    <!-- TODO replace with car support lib sizes when available -->      <dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen>      <dimen name="car_fullscreen_user_pod_width">243dp</dimen>      <dimen name="car_fullscreen_user_pod_height">356dp</dimen>      <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>      <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen> -    <dimen name="car_padding_4">20dp</dimen> + + +    <!-- Application Bar --> +    <dimen name="car_app_bar_height">80dp</dimen> +    <!-- Margin --> +    <dimen name="car_margin">20dp</dimen> +    <!-- Lists --> +    <dimen name="car_single_line_list_item_height">96dp</dimen> +    <dimen name="car_double_line_list_item_height">@dimen/car_single_line_list_item_height</dimen> +    <dimen name="car_list_divider_height">1dp</dimen> +    <!-- The diff between keyline 1 and keyline 3. --> +    <dimen name="car_keyline_1_keyline_3_diff">88dp</dimen> +    <dimen name="car_dialog_action_bar_height">@dimen/car_card_action_bar_height</dimen> +    <dimen name="car_primary_icon_size">44dp</dimen> + +    <!-- Text size for car --> +    <dimen name="car_title_size">32sp</dimen> +    <dimen name="car_title2_size">32sp</dimen> +    <dimen name="car_headline1_size">45sp</dimen> +    <dimen name="car_headline2_size">32sp</dimen> +    <dimen name="car_headline3_size">24sp</dimen> +    <dimen name="car_headline4_size">20sp</dimen>      <dimen name="car_body1_size">32sp</dimen> -</resources>
\ No newline at end of file +    <dimen name="car_body2_size">26sp</dimen> +    <dimen name="car_body3_size">16sp</dimen> +    <dimen name="car_body4_size">14sp</dimen> +    <dimen name="car_body5_size">18sp</dimen> +    <dimen name="car_label1_size">26sp</dimen> +    <dimen name="car_label2_size">64sp</dimen> +    <dimen name="car_action1_size">26sp</dimen> +    <dimen name="car_action2_size">26sp</dimen> + +    <!-- Common icon size for car app --> +    <dimen name="car_icon_size">56dp</dimen> + +    <dimen name="car_card_header_height">96dp</dimen> +    <dimen name="car_card_action_bar_height">96dp</dimen> + +    <!-- Paddings --> +    <dimen name="car_padding_1">4dp</dimen> +    <dimen name="car_padding_2">10dp</dimen> +    <dimen name="car_padding_3">16dp</dimen> +    <dimen name="car_padding_4">28dp</dimen> +    <dimen name="car_padding_5">32dp</dimen> + +    <!-- Radius --> +    <dimen name="car_radius_1">4dp</dimen> +    <dimen name="car_radius_2">8dp</dimen> +    <dimen name="car_radius_3">16dp</dimen> +    <dimen name="car_radius_5">100dp</dimen> + +    <!-- Keylines for content. --> +    <dimen name="car_keyline_1">48dp</dimen> +    <dimen name="car_keyline_2">108dp</dimen> +    <dimen name="car_keyline_3">152dp</dimen> +    <dimen name="car_keyline_4">182dp</dimen> + +    <!-- Buttons --> +    <dimen name="car_button_height">56dp</dimen> +    <dimen name="car_button_min_width">158dp</dimen> +    <dimen name="car_button_horizontal_padding">@dimen/car_padding_4</dimen> +    <dimen name="car_borderless_button_horizontal_padding">0dp</dimen> +    <dimen name="car_button_radius">@dimen/car_radius_1</dimen> +    <dimen name="car_pill_button_size">56dp</dimen> + +    <!-- Seekbar --> +    <dimen name="car_seekbar_height">6dp</dimen> +    <dimen name="car_seekbar_padding">26dp</dimen> +    <dimen name="car_seekbar_thumb_size">24dp</dimen> +    <dimen name="car_seekbar_thumb_stroke">1dp</dimen> +    <!-- The space between seekbar and text in ListItem. This value is based on car_seekbar_padding. +         It brings seekbar and text closer for visual balance while maintaining touch area. --> +    <dimen name="car_seekbar_text_overlap">-20dp</dimen> + +    <!-- Progress Bar --> +    <dimen name="car_progress_bar_height">@dimen/car_seekbar_height</dimen> + +</resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index cc99a4e4e640..fadefff6a030 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2912,6 +2912,8 @@          <!-- @hide For use by platform and tools only. Developers should not specify this value. -->          <public name="usesNonSdkApi" />          <public name="minimumUiTimeout" /> +        <public name="isLightTheme" /> +        <public name="isSplitRequired" />      </public-group>      <public-group type="drawable" first-id="0x010800b4"> diff --git a/core/res/res/values/styles_car.xml b/core/res/res/values/styles_car.xml new file mode 100644 index 000000000000..f6ff1b651788 --- /dev/null +++ b/core/res/res/values/styles_car.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> +<resources> +    <!-- Car text --> +    <style name="CarBody1"> +        <item name="textStyle">normal</item> +        <item name="textSize">@dimen/car_body1_size</item> +        <item name="textColor">@color/car_body1</item> +    </style> + +    <style name="CarBody1.Light"> +        <item name="textColor">@color/car_body1_light</item> +    </style> + +    <style name="CarBody1.Dark"> +        <item name="textColor">@color/car_body2_dark</item> +    </style> + +    <style name="CarBody2"> +        <item name="textStyle">normal</item> +        <item name="textSize">@dimen/car_body2_size</item> +        <item name="textColor">@color/car_body2</item> +    </style> + +    <style name="CarBody2.Dark"> +        <item name="textColor">@color/car_body2_dark</item> +    </style> +    <style name="CarBody2.Light"> +        <item name="textColor">@color/car_body2_light</item> +    </style> + +    <style name="CarBody3"> +        <item name="textStyle">normal</item> +        <item name="textSize">@dimen/car_body3_size</item> +        <item name="textColor">@color/car_body3</item> +    </style> + +    <!-- The smallest styling for body text. The color of this text changes based on the day/night +         mode. --> +    <style name="CarBody4"> +        <item name="textStyle">normal</item> +        <item name="textSize">@dimen/car_body4_size</item> +        <item name="textColor">@color/car_body4</item> +    </style> + +    <style name="CarAction1"> +        <item name="textStyle">bold</item> +        <item name="textSize">@dimen/car_action1_size</item> +        <item name="textColor">@color/car_highlight</item> +    </style> + +    <style name="CarAction1.Dark"> +        <item name="textColor">@color/car_highlight_dark</item> +    </style> +    <style name="CarAction1.Light"> +        <item name="textColor">@color/car_highlight_light</item> +    </style> + +    <!-- The styling for title text. The color of this text changes based on day/night mode. --> +    <style name="CarTitle" > +        <item name="textStyle">bold</item> +        <item name="textSize">@dimen/car_title2_size</item> +        <item name="textColor">@color/car_title</item> +    </style> + +    <!-- Title text that is permanently a dark color. --> +    <style name="CarTitle.Dark" > +        <item name="textColor">@color/car_title_dark</item> +    </style> + +    <!-- Title text that is permanently a light color. --> +    <style name="CarTitle.Light" > +        <item name="textColor">@color/car_title_light</item> +    </style> + +</resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 21f0dad69e2c..72ae0d61654a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3279,7 +3279,7 @@    <java-symbol type="array" name="config_hideWhenDisabled_packageNames" />    <java-symbol type="string" name="config_dozeLongPressSensorType" /> -  <java-symbol type="string" name="config_dozeReachSensorType" /> +  <java-symbol type="string" name="config_dozeWakeLockScreenSensorType" />    <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />    <java-symbol type="array" name="config_allowedSystemInstantAppSettings" /> @@ -3470,4 +3470,9 @@    <java-symbol type="integer" name="db_wal_truncate_size" />    <java-symbol type="integer" name="config_wakeUpDelayDoze" />    <java-symbol type="string" name="config_dozeWakeScreenSensorType" /> + +  <!-- For Bluetooth AbsoluteVolume --> +  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" /> +  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" /> +  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />  </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 442106b988e1..3385527ee6ff 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1716,4 +1716,10 @@ easier.          <item name="colorAccent">@color/accent_device_default_dark</item>      </style> +    <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen"> +        <item name="colorBackground">@color/background_device_default_light</item> +        <item name="colorBackgroundFloating">@color/background_device_default_light</item> +        <item name="layout_gravity">center</item> +    </style> +  </resources> diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java index 3ce258969822..6fdb71fcbab0 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;  import android.content.Context;  import android.content.res.AssetManager;  import android.graphics.fonts.Font; +import android.graphics.fonts.FontCustomizationParser;  import android.graphics.fonts.FontFamily;  import android.graphics.fonts.SystemFonts;  import android.support.test.InstrumentationRegistry; @@ -36,12 +37,15 @@ import org.junit.After;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParserException; +import java.io.ByteArrayInputStream;  import java.io.File;  import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InputStream;  import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets;  import java.nio.file.Files;  import java.nio.file.StandardCopyOption;  import java.util.ArrayList; @@ -62,6 +66,8 @@ public class TypefaceSystemFallbackTest {      };      private static final String TEST_FONTS_XML;      private static final String TEST_FONT_DIR; +    private static final String TEST_OEM_XML; +    private static final String TEST_OEM_DIR;      private static final float GLYPH_1EM_WIDTH;      private static final float GLYPH_2EM_WIDTH; @@ -73,8 +79,13 @@ public class TypefaceSystemFallbackTest {          if (!cacheDir.isDirectory()) {              cacheDir.mkdirs();          } -        TEST_FONT_DIR = cacheDir.getAbsolutePath() + "/"; +        TEST_FONT_DIR = cacheDir.getAbsolutePath() + "/fonts/";          TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath(); +        TEST_OEM_DIR = cacheDir.getAbsolutePath() + "/oem_fonts/"; +        TEST_OEM_XML = new File(cacheDir, "fonts_customization.xml").getAbsolutePath(); + +        new File(TEST_FONT_DIR).mkdirs(); +        new File(TEST_OEM_DIR).mkdirs();          final AssetManager am =                  InstrumentationRegistry.getInstrumentation().getContext().getAssets(); @@ -99,6 +110,12 @@ public class TypefaceSystemFallbackTest {              } catch (IOException e) {                  throw new RuntimeException(e);              } +            final File outOemInCache = new File(TEST_OEM_DIR, fontFile); +            try (InputStream is = am.open(sourceInAsset)) { +                Files.copy(is, outOemInCache.toPath(), StandardCopyOption.REPLACE_EXISTING); +            } catch (IOException e) { +                throw new RuntimeException(e); +            }          }      } @@ -107,11 +124,14 @@ public class TypefaceSystemFallbackTest {          for (final String fontFile : TEST_FONT_FILES) {              final File outInCache = new File(TEST_FONT_DIR, fontFile);              outInCache.delete(); +            final File outOemInCache = new File(TEST_OEM_DIR, fontFile); +            outInCache.delete();          }      }      private static void buildSystemFallback(String xml, -            ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { +            FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap, +            ArrayMap<String, FontFamily[]> fallbackMap) {          final ArrayList<Font> availableFonts = new ArrayList<>();          try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {              fos.write(xml.getBytes(Charset.forName("UTF-8"))); @@ -119,18 +139,28 @@ public class TypefaceSystemFallbackTest {              throw new RuntimeException(e);          }          final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML, -                TEST_FONT_DIR, fallbackMap, availableFonts); +                TEST_FONT_DIR, oemCustomization, fallbackMap, availableFonts);          Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);      } +    private static FontCustomizationParser.Result readFontCustomization(String oemXml) { +        try (InputStream is = new ByteArrayInputStream(oemXml.getBytes(StandardCharsets.UTF_8))) { +            return FontCustomizationParser.parse(is, TEST_OEM_DIR); +        } catch (IOException | XmlPullParserException e) { +            throw new RuntimeException(e); +        } +    } +      @Test      public void testBuildSystemFallback() {          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();          final ArrayList<Font> availableFonts = new ArrayList<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result();          final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML, -                SYSTEM_FONT_DIR, fallbackMap, availableFonts); +                SYSTEM_FONT_DIR, oemCustomization, fallbackMap, availableFonts);          assertNotNull(aliases);          assertFalse(fallbackMap.isEmpty()); @@ -156,8 +186,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          assertEquals(1, fontMap.size());          assertTrue(fontMap.containsKey("sans-serif")); @@ -184,8 +216,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -230,8 +264,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -275,8 +311,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -325,8 +363,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -371,8 +411,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -410,8 +452,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -449,8 +493,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -497,8 +543,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint();          paint.setTypeface(fontMap.get("sans-serif")); @@ -539,8 +587,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -578,8 +628,10 @@ public class TypefaceSystemFallbackTest {                  + "</familyset>";          final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result(); -        buildSystemFallback(xml, fontMap, fallbackMap); +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);          final Paint paint = new Paint(); @@ -598,4 +650,191 @@ public class TypefaceSystemFallbackTest {          assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);      } +    @Test +    public void testBuildSystemFallback__Customization_new_named_family() { +        final String xml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<familyset>" +                + "  <family name='sans-serif'>" +                + "    <font weight='400' style='normal'>a3em.ttf</font>" +                + "  </family>" +                + "</familyset>"; +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family' name='google-sans'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "</fonts-modification>"; +        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); +        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                readFontCustomization(oemXml); + +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap); + +        final Paint paint = new Paint(); + +        Typeface testTypeface = fontMap.get("sans-serif"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + +        testTypeface = fontMap.get("google-sans"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); +    } + +    @Test +    public void testBuildSystemFallback__Customization_new_named_family_override() { +        final String xml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<familyset>" +                + "  <family name='sans-serif'>" +                + "    <font weight='400' style='normal'>a3em.ttf</font>" +                + "  </family>" +                + "</familyset>"; +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family' name='sans-serif'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "</fonts-modification>"; +        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); +        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                readFontCustomization(oemXml); + +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap); + +        final Paint paint = new Paint(); + +        Typeface testTypeface = fontMap.get("sans-serif"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); +    } + +    @Test +    public void testBuildSystemFallback__Customization_additional_alias() { +        final String xml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<familyset>" +                + "  <family name='sans-serif'>" +                + "    <font weight='400' style='normal'>a3em.ttf</font>" +                + "  </family>" +                + "</familyset>"; +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family' name='google-sans'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "    <font weight='700' style='normal'>c3em.ttf</font>" +                + "  </family>" +                + "  <alias name='another-google-sans' to='google-sans' />" +                + "  <alias name='google-sans-bold' to='google-sans' weight='700' />" +                + "</fonts-modification>"; +        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); +        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                readFontCustomization(oemXml); + +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap); + +        final Paint paint = new Paint(); + +        Typeface testTypeface = fontMap.get("sans-serif"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + +        testTypeface = fontMap.get("google-sans"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + +        testTypeface = fontMap.get("another-google-sans"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + +        testTypeface = fontMap.get("google-sans-bold"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); +    } + +    @Test +    public void testBuildSystemFallback__Customization_additional_alias_conflict_with_new_name() { +        final String xml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<familyset>" +                + "  <family name='named-family'>" +                + "    <font weight='400' style='normal'>a3em.ttf</font>" +                + "  </family>" +                + "  <alias name='named-alias' to='named-family' />" +                + "</familyset>"; +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family' name='named-alias'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "</fonts-modification>"; +        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); +        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); +        final FontCustomizationParser.Result oemCustomization = +                readFontCustomization(oemXml); + +        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap); + +        final Paint paint = new Paint(); + +        Typeface testTypeface = fontMap.get("named-family"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + +        testTypeface = fontMap.get("named-alias"); +        assertNotNull(testTypeface); +        paint.setTypeface(testTypeface); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); +        assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); +        assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); +    } + +    @Test(expected = IllegalArgumentException.class) +    public void testBuildSystemFallback__Customization_new_named_family_no_name_exception() { +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "</fonts-modification>"; +        readFontCustomization(oemXml); +    } + +    @Test(expected = IllegalArgumentException.class) +    public void testBuildSystemFallback__Customization_new_named_family_dup_name_exception() { +        final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" +                + "<fonts-modification version='1'>" +                + "  <family customizationType='new-named-family' name='google-sans'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "  <family customizationType='new-named-family' name='google-sans'>" +                + "    <font weight='400' style='normal'>b3em.ttf</font>" +                + "  </family>" +                + "</fonts-modification>"; +        readFontCustomization(oemXml); +    }  } diff --git a/core/tests/coretests/src/android/net/LocalSocketTest.java b/core/tests/coretests/src/android/net/LocalSocketTest.java index 1349844c80cf..1286b137cc1f 100644 --- a/core/tests/coretests/src/android/net/LocalSocketTest.java +++ b/core/tests/coretests/src/android/net/LocalSocketTest.java @@ -22,6 +22,7 @@ import android.net.LocalSocket;  import android.net.LocalSocketAddress;  import android.test.MoreAsserts;  import android.test.suitebuilder.annotation.SmallTest; +  import junit.framework.TestCase;  import java.io.FileDescriptor; @@ -39,6 +40,20 @@ public class LocalSocketTest extends TestCase {          ls = new LocalSocket(); +        try { +            ls.connect(new LocalSocketAddress(null)); +            fail("Expected NullPointerException"); +        } catch (NullPointerException e) { +            // pass +        } + +        try { +            ls.bind(new LocalSocketAddress(null)); +            fail("Expected NullPointerException"); +        } catch (NullPointerException e) { +            // pass +        } +          ls.connect(new LocalSocketAddress("android.net.LocalSocketTest"));          ls1 = ss.accept(); diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index fee470dce24d..d2420ee1ef10 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -114,6 +114,7 @@ public class SettingsBackupTest {                      Settings.Global.ANOMALY_CONFIG_VERSION,                      Settings.Global.APN_DB_UPDATE_CONTENT_URL,                      Settings.Global.APN_DB_UPDATE_METADATA_URL, +                    Settings.Global.APP_BINDING_CONSTANTS,                      Settings.Global.APP_IDLE_CONSTANTS,                      Settings.Global.APP_OPS_CONSTANTS,                      Settings.Global.APP_STANDBY_ENABLED, @@ -447,6 +448,7 @@ public class SettingsBackupTest {                      Settings.Global.ENABLE_GPU_DEBUG_LAYERS,                      Settings.Global.GPU_DEBUG_APP,                      Settings.Global.GPU_DEBUG_LAYERS, +                    Settings.Global.ANGLE_ENABLED_APP,                      Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,                      Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,                      Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS, diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java index 890929374159..b0d29bd1d8f0 100644 --- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java +++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java @@ -73,7 +73,7 @@ public class SettingsValidatorsTest {      @Test      public void testComponentNameValidator() {          assertTrue(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate( -                "android/com.android.internal.backup.LocalTransport")); +                "com.android.localtransport/.LocalTransport"));          assertFalse(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate("rectangle"));      } @@ -90,7 +90,7 @@ public class SettingsValidatorsTest {      @Test      public void testNullableComponentNameValidator_onValidComponentName_returnsTrue() {          assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate( -                "android/com.android.internal.backup.LocalTransport")); +                "com.android.localtransport/.LocalTransport"));      }      @Test @@ -185,7 +185,7 @@ public class SettingsValidatorsTest {      @Test      public void testComponentNameListValidator() {          Validator v = new SettingsValidators.ComponentNameListValidator(","); -        assertTrue(v.validate("android/com.android.internal.backup.LocalTransport," +        assertTrue(v.validate("com.android.localtransport/.LocalTransport,"                  + "com.google.android.gms/.backup.migrate.service.D2dTransport"));          assertFalse(v.validate("com.google.5android,android"));      } @@ -200,7 +200,7 @@ public class SettingsValidatorsTest {      @Test      public void testPackageNameListValidator() {          Validator v = new SettingsValidators.PackageNameListValidator(","); -        assertTrue(v.validate("com.android.internal.backup.LocalTransport,com.google.android.gms")); +        assertTrue(v.validate("com.android.localtransport.LocalTransport,com.google.android.gms"));          assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android"));      } diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java index 898e78c651e6..5592aac5a7c0 100644 --- a/core/tests/coretests/src/android/text/FontFallbackSetup.java +++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java @@ -21,6 +21,7 @@ import android.content.Context;  import android.content.res.AssetManager;  import android.graphics.Typeface;  import android.graphics.fonts.Font; +import android.graphics.fonts.FontCustomizationParser;  import android.graphics.fonts.FontFamily;  import android.graphics.fonts.SystemFonts;  import android.support.test.InstrumentationRegistry; @@ -77,8 +78,10 @@ public class FontFallbackSetup implements AutoCloseable {          final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();          final ArrayList<Font> availableFonts = new ArrayList<>(); +        final FontCustomizationParser.Result oemCustomization = +                new FontCustomizationParser.Result();          final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml, -                mTestFontsDir, fallbackMap, availableFonts); +                mTestFontsDir, oemCustomization, fallbackMap, availableFonts);          Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);      } diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java index efdd7e978853..8360126f3751 100644 --- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java @@ -43,7 +43,7 @@ import java.util.Random;  /**   * Test class for {@link KernelCpuProcReader}.   * - * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuProcReader + * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuProcReaderTest   */  @SmallTest  @RunWith(AndroidJUnit4.class) diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java new file mode 100644 index 000000000000..c051a1cdf052 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.content.Context; +import android.os.FileUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.BufferedWriter; +import java.io.File; +import java.nio.file.Files; + + +/** + * Test class for {@link StoragedUidIoStatsReader}. + * + * To run it: + * atest FrameworksCoreTests:com.android.internal.os.StoragedUidIoStatsReaderTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class StoragedUidIoStatsReaderTest { + +    private File mRoot; +    private File mTestDir; +    private File mTestFile; +    // private Random mRand = new Random(); + +    private StoragedUidIoStatsReader mStoragedUidIoStatsReader; +    @Mock +    private StoragedUidIoStatsReader.Callback mCallback; + +    private Context getContext() { +        return InstrumentationRegistry.getContext(); +    } + +    @Before +    public void setUp() { +        MockitoAnnotations.initMocks(this); +        mTestDir = getContext().getDir("test", Context.MODE_PRIVATE); +        mRoot = getContext().getFilesDir(); +        mTestFile = new File(mTestDir, "test.file"); +        mStoragedUidIoStatsReader = new StoragedUidIoStatsReader(mTestFile.getAbsolutePath()); +    } + +    @After +    public void tearDown() throws Exception { +        FileUtils.deleteContents(mTestDir); +        FileUtils.deleteContents(mRoot); +    } + + +    /** +     * Tests that reading will never call the callback. +     */ +    @Test +    public void testReadNonexistentFile() throws Exception { +        mStoragedUidIoStatsReader.readAbsolute(mCallback); +        verifyZeroInteractions(mCallback); + +    } + +    /** +     * Tests that reading a file with 3 uids works as expected. +     */ +    @Test +    public void testReadExpected() throws Exception { +        BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath()); +        int[] uids = {0, 100, 200}; +        long[] fg_chars_read = {1L, 101L, 201L}; +        long[] fg_chars_write = {2L, 102L, 202L}; +        long[] fg_bytes_read = {3L, 103L, 203L}; +        long[] fg_bytes_write = {4L, 104L, 204L}; +        long[] bg_chars_read = {5L, 105L, 205L}; +        long[] bg_chars_write = {6L, 106L, 206L}; +        long[] bg_bytes_read = {7L, 107L, 207L}; +        long[] bg_bytes_write = {8L, 108L, 208L}; +        long[] fg_fsync = {9L, 109L, 209L}; +        long[] bg_fsync = {10L, 110L, 210L}; + +        for (int i = 0; i < uids.length; i++) { +            bufferedWriter.write(String +                    .format("%d %d %d %d %d %d %d %d %d %d %d\n", uids[i], fg_chars_read[i], +                            fg_chars_write[i], fg_bytes_read[i], fg_bytes_write[i], +                            bg_chars_read[i], bg_chars_write[i], bg_bytes_read[i], +                            bg_bytes_write[i], fg_fsync[i], bg_fsync[i])); +        } +        bufferedWriter.close(); + +        mStoragedUidIoStatsReader.readAbsolute(mCallback); +        for (int i = 0; i < uids.length; i++) { +            verify(mCallback).onUidStorageStats(uids[i], fg_chars_read[i], fg_chars_write[i], +                    fg_bytes_read[i], fg_bytes_write[i], bg_chars_read[i], bg_chars_write[i], +                    bg_bytes_read[i], bg_bytes_write[i], fg_fsync[i], bg_fsync[i]); +        } +        verifyNoMoreInteractions(mCallback); + +    } + +    /** +     * Tests that a line with less than 11 items is passed over. +     */ +    @Test +    public void testLineDoesNotElevenEntries() throws Exception { +        BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath()); + +        // Only has 10 numbers. +        bufferedWriter.write(String +                .format("%d %d %d %d %d %d %d %d %d %d\n", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); + +        bufferedWriter.write(String +                .format("%d %d %d %d %d %d %d %d %d %d %d\n", 10, 11, 12, 13, 14, 15, 16, 17, 18, +                        19, 20)); +        bufferedWriter.close(); + +        // Make sure we get the second line, but the first is skipped. +        mStoragedUidIoStatsReader.readAbsolute(mCallback); +        verify(mCallback).onUidStorageStats(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); +        verifyNoMoreInteractions(mCallback); +    } + + +    /** +     * Tests that a line that is malformed is passed over. +     */ +    @Test +    public void testLineIsMalformed() throws Exception { +        BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath()); + +        // Line is not formatted properly. It has a string. +        bufferedWriter.write(String +                .format("%d %d %d %d %d %s %d %d %d %d %d\n", 0, 1, 2, 3, 4, "NotANumber", 5, 6, 7, +                        8, 9)); + +        bufferedWriter.write(String +                .format("%d %d %d %d %d %d %d %d %d %d %d\n", 10, 11, 12, 13, 14, 15, 16, 17, 18, +                        19, 20)); +        bufferedWriter.close(); + +        // Make sure we get the second line, but the first is skipped. +        mStoragedUidIoStatsReader.readAbsolute(mCallback); +        verify(mCallback).onUidStorageStats(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); +        verifyNoMoreInteractions(mCallback); +    } +} diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml index ae6a7f6d6808..b0d2de17527d 100644 --- a/data/etc/framework-sysconfig.xml +++ b/data/etc/framework-sysconfig.xml @@ -28,7 +28,7 @@      <!-- Whitelist of what components are permitted as backup data transports.  The           'service' attribute here is a flattened ComponentName string. -->      <backup-transport-whitelisted-service -        service="android/com.android.internal.backup.LocalTransportService" /> +        service="com.android.localtransport/.LocalTransportService" />      <!-- Whitelist of bundled applications which all handle URLs to their websites by default -->      <app-link package="com.android.carrierdefaultapp" /> diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index 76eb4e676923..454dceb9c82c 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -89,23 +89,7 @@ include $(CLEAR_VARS)  LOCAL_MODULE := fonts.xml  LOCAL_MODULE_CLASS := ETC - -AOSP_FONTS_FILE := frameworks/base/data/fonts/fonts.xml - -ifdef ADDITIONAL_FONTS_FILE -ADDITIONAL_FONTS_SCRIPT := frameworks/base/tools/fonts/add_additional_fonts.py -ADD_ADDITIONAL_FONTS := $(local-generated-sources-dir)/fonts.xml - -$(ADD_ADDITIONAL_FONTS): PRIVATE_SCRIPT := $(ADDITIONAL_FONTS_SCRIPT) -$(ADD_ADDITIONAL_FONTS): PRIVATE_ADDITIONAL_FONTS_FILE := $(ADDITIONAL_FONTS_FILE) -$(ADD_ADDITIONAL_FONTS): $(ADDITIONAL_FONTS_SCRIPT) $(AOSP_FONTS_FILE) $(ADDITIONAL_FONTS_FILE) -	rm -f $@ -	python $(PRIVATE_SCRIPT) $@ $(PRIVATE_ADDITIONAL_FONTS_FILE) -else -ADD_ADDITIONAL_FONTS := $(AOSP_FONTS_FILE) -endif - -LOCAL_PREBUILT_MODULE_FILE := $(ADD_ADDITIONAL_FONTS) +LOCAL_PREBUILT_MODULE_FILE := frameworks/base/data/fonts/fonts.xml  include $(BUILD_PREBUILT) diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 53e9826998f3..fa37bedb06c4 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -28,11 +28,10 @@ import android.text.PrecomputedText;  import android.text.SpannableString;  import android.text.SpannedString;  import android.text.TextUtils; -import android.view.RecordingCanvas;  /**   * This class is a base class for Canvas's drawing operations. Any modifications here - * should be accompanied by a similar modification to {@link RecordingCanvas}. + * should be accompanied by a similar modification to {@link BaseRecordingCanvas}.   *   * The purpose of this class is to minimize the cost of deciding between regular JNI   * and @FastNative JNI to just the virtual call that Canvas already has. diff --git a/core/java/android/view/RecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index 33644832bdf1..6e936910ef40 100644 --- a/core/java/android/view/RecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -14,25 +14,12 @@   * limitations under the License.   */ -package android.view; +package android.graphics;  import android.annotation.ColorInt;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.Size; -import android.graphics.BaseCanvas; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.NinePatch; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Picture; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.TemporaryBuffer;  import android.text.GraphicsOperations;  import android.text.MeasuredParagraph;  import android.text.PrecomputedText; @@ -49,9 +36,9 @@ import dalvik.annotation.optimization.FastNative;   *   * @hide   */ -public class RecordingCanvas extends Canvas { +public class BaseRecordingCanvas extends Canvas { -    public RecordingCanvas(long nativeCanvas) { +    public BaseRecordingCanvas(long nativeCanvas) {          super(nativeCanvas);      } diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 82435d5511f5..21cc3757a40e 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -40,17 +40,25 @@ public class FontListParser {      /* Parse fallback list (no names) */      @UnsupportedAppUsage      public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException { +        return parse(in, "/system/fonts"); +    } + +    /** +     * Parse the fonts.xml +     */ +    public static FontConfig parse(InputStream in, String fontDir) +            throws XmlPullParserException, IOException {          try {              XmlPullParser parser = Xml.newPullParser();              parser.setInput(in, null);              parser.nextTag(); -            return readFamilies(parser); +            return readFamilies(parser, fontDir);          } finally {              in.close();          }      } -    private static FontConfig readFamilies(XmlPullParser parser) +    private static FontConfig readFamilies(XmlPullParser parser, String fontDir)              throws XmlPullParserException, IOException {          List<FontConfig.Family> families = new ArrayList<>();          List<FontConfig.Alias> aliases = new ArrayList<>(); @@ -60,7 +68,7 @@ public class FontListParser {              if (parser.getEventType() != XmlPullParser.START_TAG) continue;              String tag = parser.getName();              if (tag.equals("family")) { -                families.add(readFamily(parser)); +                families.add(readFamily(parser, fontDir));              } else if (tag.equals("alias")) {                  aliases.add(readAlias(parser));              } else { @@ -71,7 +79,10 @@ public class FontListParser {                  aliases.toArray(new FontConfig.Alias[aliases.size()]));      } -    private static FontConfig.Family readFamily(XmlPullParser parser) +    /** +     * Reads a family element +     */ +    public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir)              throws XmlPullParserException, IOException {          final String name = parser.getAttributeValue(null, "name");          final String lang = parser.getAttributeValue("", "lang"); @@ -81,7 +92,7 @@ public class FontListParser {              if (parser.getEventType() != XmlPullParser.START_TAG) continue;              final String tag = parser.getName();              if (tag.equals("font")) { -                fonts.add(readFont(parser)); +                fonts.add(readFont(parser, fontDir));              } else {                  skip(parser);              } @@ -102,7 +113,7 @@ public class FontListParser {      private static final Pattern FILENAME_WHITESPACE_PATTERN =              Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); -    private static FontConfig.Font readFont(XmlPullParser parser) +    private static FontConfig.Font readFont(XmlPullParser parser, String fontDir)              throws XmlPullParserException, IOException {          String indexStr = parser.getAttributeValue(null, "index");          int index = indexStr == null ? 0 : Integer.parseInt(indexStr); @@ -125,7 +136,7 @@ public class FontListParser {              }          }          String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); -        return new FontConfig.Font(sanitizedName, index, axes.toArray( +        return new FontConfig.Font(fontDir + sanitizedName, index, axes.toArray(                  new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);      } @@ -137,7 +148,10 @@ public class FontListParser {          return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr));      } -    private static FontConfig.Alias readAlias(XmlPullParser parser) +    /** +     * Reads alias elements +     */ +    public static FontConfig.Alias readAlias(XmlPullParser parser)              throws XmlPullParserException, IOException {          String name = parser.getAttributeValue(null, "name");          String toName = parser.getAttributeValue(null, "to"); @@ -152,7 +166,10 @@ public class FontListParser {          return new FontConfig.Alias(name, toName, weight);      } -    private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException { +    /** +     * Skip until next element +     */ +    public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {          int depth = 1;          while (depth > 0) {              switch (parser.next()) { diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index 4fec33f19d92..c4dc0adb3be0 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -23,8 +23,11 @@ import android.annotation.UnsupportedAppUsage;  import android.os.Parcel;  import android.os.Parcelable;  import android.text.TextUtils; +import android.util.proto.ProtoInputStream;  import android.util.proto.ProtoOutputStream; +import android.util.proto.WireTypeMismatchException; +import java.io.IOException;  import java.io.PrintWriter;  import java.util.regex.Matcher;  import java.util.regex.Pattern; @@ -232,6 +235,40 @@ public final class Rect implements Parcelable {      }      /** +     * Read from a protocol buffer input stream. +     * Protocol buffer message definition at {@link android.graphics.RectProto} +     * +     * @param proto     Stream to read the Rect object from. +     * @param fieldId   Field Id of the Rect as defined in the parent message +     * @hide +     */ +    public void readFromProto(@NonNull ProtoInputStream proto, long fieldId) throws IOException, +            WireTypeMismatchException { +        final long token = proto.start(fieldId); +        try { +            while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +                switch (proto.getFieldNumber()) { +                    case (int) RectProto.LEFT: +                        left = proto.readInt(RectProto.LEFT); +                        break; +                    case (int) RectProto.TOP: +                        top = proto.readInt(RectProto.TOP); +                        break; +                    case (int) RectProto.RIGHT: +                        right = proto.readInt(RectProto.RIGHT); +                        break; +                    case (int) RectProto.BOTTOM: +                        bottom = proto.readInt(RectProto.BOTTOM); +                        break; +                } +            } +        } finally { +            // Let caller handle any exceptions +            proto.end(token); +        } +    } + +    /**       * Returns true if the rectangle is empty (left >= right or top >= bottom)       */      public final boolean isEmpty() { diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 492c236c014e..7ad207f339d1 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -34,7 +34,6 @@ import android.os.Build;  import android.provider.FontRequest;  import android.provider.FontsContract;  import android.text.FontConfig; -import android.util.ArrayMap;  import android.util.Base64;  import android.util.LongSparseArray;  import android.util.LruCache; @@ -1104,6 +1103,9 @@ public class Typeface {          }          for (FontConfig.Alias alias : aliases) { +            if (systemFontMap.containsKey(alias.getName())) { +                continue; // If alias and named family are conflict, use named family. +            }              final Typeface base = systemFontMap.get(alias.getToName());              final int weight = alias.getWeight();              final Typeface newFace = weight == 400 ? base : @@ -1112,13 +1114,6 @@ public class Typeface {          }      } -    // Following methods are left for layoutlib -    // TODO: Remove once layoutlib stop calling buildSystemFallback -    /** @hide */ -    public static void buildSystemFallback(String xmlPath, String fontDir, -            ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { -    } -      static {          final HashMap<String, Typeface> systemFontMap = new HashMap<>();          initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 76f2cfb33824..6c1372ff25b4 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -51,6 +51,7 @@ import android.util.Property;  import android.util.TimeUtils;  import android.view.Choreographer;  import android.view.DisplayListCanvas; +import android.view.NativeVectorDrawableAnimator;  import android.view.RenderNode;  import android.view.RenderNodeAnimatorSetHelper;  import android.view.View; @@ -1231,7 +1232,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {      /**       * @hide       */ -    public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator { +    public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator, +            NativeVectorDrawableAnimator {          private static final int START_ANIMATION = 1;          private static final int REVERSE_ANIMATION = 2;          private static final int RESET_ANIMATION = 3; @@ -1704,6 +1706,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {              }          } +        @Override          public long getAnimatorNativePtr() {              return mSetPtr;          } diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 1458c66a2c54..bd1ac25bf8df 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -422,9 +422,10 @@ public final class Font {                      nAddAxis(builderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue());                  }              } -            final long ptr = nBuild(builderPtr, mBuffer, mWeight, italic, mTtcIndex); -            final Font font = new Font(ptr, mBuffer, mFile, mWeight, italic, mTtcIndex, mAxes, -                    mLocaleList); +            final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer(); +            final long ptr = nBuild(builderPtr, readonlyBuffer, mWeight, italic, mTtcIndex); +            final Font font = new Font(ptr, readonlyBuffer, mFile, mWeight, italic, mTtcIndex, +                    mAxes, mLocaleList);              sFontRegistory.registerNativeAllocation(font, ptr);              return font;          } @@ -477,7 +478,7 @@ public final class Font {      }      /** -     * Retuns a font file buffer. +     * Returns a font file buffer.       *       * @return a font buffer       */ diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java new file mode 100644 index 000000000000..0291d7484dc5 --- /dev/null +++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java @@ -0,0 +1,105 @@ +/* + * 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.graphics.fonts; + +import android.annotation.NonNull; +import android.graphics.FontListParser; +import android.text.FontConfig; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; + +/** + * Parser for font customization + * + * @hide + */ +public class FontCustomizationParser { +    /** +     * Represents a customization XML +     */ +    public static class Result { +        ArrayList<FontConfig.Family> mAdditionalNamedFamilies = new ArrayList<>(); +        ArrayList<FontConfig.Alias> mAdditionalAliases = new ArrayList<>(); +    } + +    /** +     * Parses the customization XML +     * +     * Caller must close the input stream +     */ +    public static Result parse(@NonNull InputStream in, @NonNull String fontDir) +            throws XmlPullParserException, IOException { +        XmlPullParser parser = Xml.newPullParser(); +        parser.setInput(in, null); +        parser.nextTag(); +        return readFamilies(parser, fontDir); +    } + +    private static void validate(Result result) { +        HashSet<String> familyNames = new HashSet<>(); +        for (int i = 0; i < result.mAdditionalNamedFamilies.size(); ++i) { +            final FontConfig.Family family = result.mAdditionalNamedFamilies.get(i); +            final String name = family.getName(); +            if (name == null) { +                throw new IllegalArgumentException("new-named-family requires name attribute"); +            } +            if (!familyNames.add(name)) { +                throw new IllegalArgumentException( +                        "new-named-family requires unique name attribute"); +            } +        } +    } + +    private static Result readFamilies(XmlPullParser parser, String fontDir) +            throws XmlPullParserException, IOException { +        Result out = new Result(); +        parser.require(XmlPullParser.START_TAG, null, "fonts-modification"); +        while (parser.next() != XmlPullParser.END_TAG) { +            if (parser.getEventType() != XmlPullParser.START_TAG) continue; +            String tag = parser.getName(); +            if (tag.equals("family")) { +                readFamily(parser, fontDir, out); +            } else if (tag.equals("alias")) { +                out.mAdditionalAliases.add(FontListParser.readAlias(parser)); +            } else { +                FontListParser.skip(parser); +            } +        } +        validate(out); +        return out; +    } + +    private static void readFamily(XmlPullParser parser, String fontDir, Result out) +            throws XmlPullParserException, IOException { +        final String customizationType = parser.getAttributeValue(null, "customizationType"); +        if (customizationType == null) { +            throw new IllegalArgumentException("customizationType must be specified"); +        } +        if (customizationType.equals("new-named-family")) { +            out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir)); +        } else { +            throw new IllegalArgumentException("Unknown customizationType=" + customizationType); +        } +    } +} diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index f4a2199a6688..2d21bbbd4e43 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -45,7 +45,7 @@ import java.util.Set;  /**   * Provides the system font configurations.   */ -public class SystemFonts { +public final class SystemFonts {      private static final String TAG = "SystemFonts";      private static final String DEFAULT_FAMILY = "sans-serif"; @@ -58,8 +58,7 @@ public class SystemFonts {      /**       * Returns all available font files in the system.       * -     * Note: The order of this font doesn't indicates anything. -     * @return an array of system fonts +     * @return a set of system fonts       */      public static @NonNull Set<Font> getAvailableFonts() {          HashSet<Font> set = new HashSet<>(); @@ -114,7 +113,6 @@ public class SystemFonts {      private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily,              @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,              @NonNull Map<String, ByteBuffer> cache, -            @NonNull String fontDir,              @NonNull ArrayList<Font> availableFonts) {          final String languageTags = xmlFamily.getLanguages(); @@ -139,8 +137,7 @@ public class SystemFonts {          }          final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( -                xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir, -                availableFonts); +                xmlFamily.getName(), defaultFonts, languageTags, variant, cache, availableFonts);          // Insert family into fallback map.          for (int i = 0; i < fallbackMap.size(); i++) { @@ -152,7 +149,7 @@ public class SystemFonts {                  }              } else {                  final FontFamily family = createFontFamily( -                        xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir, +                        xmlFamily.getName(), fallback, languageTags, variant, cache,                          availableFonts);                  if (family != null) {                      fallbackMap.valueAt(i).add(family); @@ -170,7 +167,6 @@ public class SystemFonts {              @NonNull String languageTags,              @FontConfig.Family.Variant int variant,              @NonNull Map<String, ByteBuffer> cache, -            @NonNull String fontDir,              @NonNull ArrayList<Font> availableFonts) {          if (fonts.size() == 0) {              return null; @@ -179,7 +175,7 @@ public class SystemFonts {          FontFamily.Builder b = null;          for (int i = 0; i < fonts.size(); i++) {              final FontConfig.Font fontConfig = fonts.get(i); -            final String fullPath = fontDir + fontConfig.getFontName(); +            final String fullPath = fontConfig.getFontName();              ByteBuffer buffer = cache.get(fullPath);              if (buffer == null) {                  if (cache.containsKey(fullPath)) { @@ -214,6 +210,22 @@ public class SystemFonts {          return b == null ? null : b.build(languageTags, variant);      } +    private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily, +            @NonNull HashMap<String, ByteBuffer> bufferCache, +            @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap, +            @NonNull ArrayList<Font> availableFonts) { +        final String familyName = xmlFamily.getName(); +        final FontFamily family = createFontFamily( +                familyName, Arrays.asList(xmlFamily.getFonts()), +                xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, availableFonts); +        if (family == null) { +            return; +        } +        final ArrayList<FontFamily> fallback = new ArrayList<>(); +        fallback.add(family); +        fallbackListMap.put(familyName, fallback); +    } +      /**       * Build the system fallback from xml file.       * @@ -227,11 +239,12 @@ public class SystemFonts {      @VisibleForTesting      public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,              @NonNull String fontDir, +            @NonNull FontCustomizationParser.Result oemCustomization,              @NonNull ArrayMap<String, FontFamily[]> fallbackMap,              @NonNull ArrayList<Font> availableFonts) {          try {              final FileInputStream fontsIn = new FileInputStream(xmlPath); -            final FontConfig fontConfig = FontListParser.parse(fontsIn); +            final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir);              final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();              final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies(); @@ -243,16 +256,12 @@ public class SystemFonts {                  if (familyName == null) {                      continue;                  } -                final FontFamily family = createFontFamily( -                        xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()), -                        xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir, -                        availableFonts); -                if (family == null) { -                    continue; -                } -                final ArrayList<FontFamily> fallback = new ArrayList<>(); -                fallback.add(family); -                fallbackListMap.put(familyName, fallback); +                appendNamedFamily(xmlFamily, bufferCache, fallbackListMap, availableFonts); +            } + +            for (int i = 0; i < oemCustomization.mAdditionalNamedFamilies.size(); ++i) { +                appendNamedFamily(oemCustomization.mAdditionalNamedFamilies.get(i), +                        bufferCache, fallbackListMap, availableFonts);              }              // Then, add fallback fonts to the each fallback map. @@ -261,8 +270,7 @@ public class SystemFonts {                  // The first family (usually the sans-serif family) is always placed immediately                  // after the primary family in the fallback.                  if (i == 0 || xmlFamily.getName() == null) { -                    pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir, -                            availableFonts); +                    pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, availableFonts);                  }              } @@ -275,20 +283,36 @@ public class SystemFonts {                  fallbackMap.put(fallbackName, families);              } -            return fontConfig.getAliases(); +            final ArrayList<FontConfig.Alias> list = new ArrayList<>(); +            list.addAll(Arrays.asList(fontConfig.getAliases())); +            list.addAll(oemCustomization.mAdditionalAliases); +            return list.toArray(new FontConfig.Alias[list.size()]);          } catch (IOException | XmlPullParserException e) {              Log.e(TAG, "Failed initialize system fallbacks.", e);              return ArrayUtils.emptyArray(FontConfig.Alias.class);          }      } +    private static FontCustomizationParser.Result readFontCustomization( +            @NonNull String customizeXml, @NonNull String customFontsDir) { +        try (FileInputStream f = new FileInputStream(customizeXml)) { +            return FontCustomizationParser.parse(f, customFontsDir); +        } catch (IOException e) { +            return new FontCustomizationParser.Result(); +        } catch (XmlPullParserException e) { +            Log.e(TAG, "Failed to parse font customization XML", e); +            return new FontCustomizationParser.Result(); +        } +    } +      static {          final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();          final ArrayList<Font> availableFonts = new ArrayList<>(); +        final FontCustomizationParser.Result oemCustomization = +                readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");          sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", -                systemFallbackMap, availableFonts); +                oemCustomization, systemFallbackMap, availableFonts);          sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);          sAvailableFonts = Collections.unmodifiableList(availableFonts);      } -  } diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h index e4cd6a8ab6b8..6c9eee0b8835 100644 --- a/libs/androidfw/include/androidfw/Util.h +++ b/libs/androidfw/include/androidfw/Util.h @@ -47,11 +47,11 @@ class unique_cptr {    constexpr unique_cptr() : ptr_(nullptr) {}    constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}    explicit unique_cptr(pointer ptr) : ptr_(ptr) {} -  unique_cptr(unique_cptr&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr; } +  unique_cptr(unique_cptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }    ~unique_cptr() { std::free(reinterpret_cast<void*>(ptr_)); } -  inline unique_cptr& operator=(unique_cptr&& o) { +  inline unique_cptr& operator=(unique_cptr&& o) noexcept {      if (&o == this) {        return *this;      } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 11dad2e0d731..494e5135d5bb 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -229,6 +229,7 @@ cc_defaults {          "ResourceCache.cpp",          "SkiaCanvas.cpp",          "Snapshot.cpp", +        "TreeInfo.cpp",          "VectorDrawable.cpp",          "protos/graphicsstats.proto",      ], diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 21fbbdca7ad0..0b9d82b105a3 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -61,18 +61,6 @@ DisplayInfo QueryDisplayInfo() {      return displayInfo;  } -void QueryCompositionPreference(ui::Dataspace* dataSpace, -                                ui::PixelFormat* pixelFormat) { -    if (Properties::isolatedProcess) { -        *dataSpace = ui::Dataspace::V0_SRGB; -        *pixelFormat = ui::PixelFormat::RGBA_8888; -    } - -    status_t status = -            SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat); -    LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status); -} -  DeviceInfo::DeviceInfo() {  #if HWUI_NULL_GPU          mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE; @@ -80,7 +68,6 @@ DeviceInfo::DeviceInfo() {          mMaxTextureSize = -1;  #endif      mDisplayInfo = QueryDisplayInfo(); -    QueryCompositionPreference(&mTargetDataSpace, &mTargetPixelFormat);  }  int DeviceInfo::maxTextureSize() const { diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index 1d7477416077..595621573e6e 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -17,7 +17,6 @@  #define DEVICEINFO_H  #include <ui/DisplayInfo.h> -#include <ui/GraphicTypes.h>  #include "utils/Macros.h" @@ -37,9 +36,6 @@ public:      // this value is only valid after the GPU has been initialized and there is a valid graphics      // context or if you are using the HWUI_NULL_GPU      int maxTextureSize() const; - -    ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; } -    ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; }      const DisplayInfo& displayInfo() const { return mDisplayInfo; }  private: @@ -50,10 +46,6 @@ private:      int mMaxTextureSize;      DisplayInfo mDisplayInfo; - -    // TODO(lpy) Replace below with android_ prefix types. -    ui::Dataspace mTargetDataSpace; -    ui::PixelFormat mTargetPixelFormat;  };  } /* namespace uirenderer */ diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 17bec1934490..a699e2f7195b 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -61,6 +61,7 @@ bool Properties::filterOutTestOverhead = false;  bool Properties::disableVsync = false;  bool Properties::skpCaptureEnabled = false;  bool Properties::forceDarkMode = false; +bool Properties::enableForceDarkSupport = false;  bool Properties::enableRTAnimations = true;  bool Properties::runningInEmulator = false; @@ -149,6 +150,9 @@ bool Properties::load() {      forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false); +    // TODO: make this on by default +    enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, false); +      return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||             (prevDebugStencilClip != debugStencilClip);  } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index ea017a72cd74..542bc71f7c72 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -192,6 +192,8 @@ enum DebugLevel {  #define PROPERTY_FORCE_DARK "debug.hwui.force_dark" +#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled" +  ///////////////////////////////////////////////////////////////////////////////  // Misc  /////////////////////////////////////////////////////////////////////////////// @@ -266,6 +268,7 @@ public:      static bool skpCaptureEnabled;      static bool forceDarkMode; +    static bool enableForceDarkSupport;      // For experimentation b/68769804      ANDROID_API static bool enableRTAnimations; diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp new file mode 100644 index 000000000000..808a12a311e2 --- /dev/null +++ b/libs/hwui/TreeInfo.cpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include "TreeInfo.h" + +#include "renderthread/CanvasContext.h" + +namespace android::uirenderer { + +TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext) +        : mode(mode) +        , prepareTextures(mode == MODE_FULL) +        , canvasContext(canvasContext) +        , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {} + +}  // namespace android::uirenderer diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index caa5762d174a..a0d960527ca6 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -16,8 +16,8 @@  #pragma once -#include "utils/Macros.h"  #include "Properties.h" +#include "utils/Macros.h"  #include <utils/Timers.h> @@ -40,7 +40,7 @@ public:      virtual void onError(const std::string& message) = 0;  protected: -    virtual ~ErrorHandler() {} +    virtual ~ErrorHandler() = default;  };  class TreeObserver { @@ -52,7 +52,7 @@ public:      virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;  protected: -    virtual ~TreeObserver() {} +    virtual ~TreeObserver() = default;  };  // This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN @@ -71,8 +71,7 @@ public:          MODE_RT_ONLY,      }; -    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext) -            : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {} +    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext);      TraversalMode mode;      // TODO: Remove this? Currently this is used to signal to stop preparing @@ -94,7 +93,7 @@ public:      bool updateWindowPositions = false; -    int disableForceDark = Properties::forceDarkMode ? 0 : 1; +    int disableForceDark;      struct Out {          bool hasFunctors = false; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index e8bf4922cd46..d401b385075e 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -167,6 +167,12 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,          mEglSurface = mEglManager.createSurface(surface, colorMode);      } +    if (colorMode == ColorMode::SRGB) { +        mSurfaceColorType = SkColorType::kN32_SkColorType; +    } else if (colorMode == ColorMode::WideColorGamut) { +        mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType; +    } +      if (mEglSurface != EGL_NO_SURFACE) {          const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);          mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); @@ -184,14 +190,6 @@ bool SkiaOpenGLPipeline::isContextReady() {      return CC_LIKELY(mEglManager.hasEglContext());  } -SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const { -    return mEglManager.getSurfaceColorType(); -} - -sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() { -    return mEglManager.getSurfaceColorSpace(); -} -  void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {      DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;      if (thread.eglManager().hasEglContext()) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 086a76088a75..4ab3541d447b 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -47,8 +47,6 @@ public:      void onStop() override;      bool isSurfaceReady() override;      bool isContextReady() override; -    SkColorType getSurfaceColorType() const override; -    sk_sp<SkColorSpace> getSurfaceColorSpace() override;      static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index ee9158c5ffc1..42a411a6808c 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -48,6 +48,9 @@ public:      bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,                               ErrorHandler* errorHandler) override; +    SkColorType getSurfaceColorType() const { return mSurfaceColorType; } +    sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; } +      void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,                       const std::vector<sp<RenderNode>>& nodes, bool opaque,                       const Rect& contentDrawBounds, sk_sp<SkSurface> surface); @@ -106,6 +109,8 @@ protected:      void dumpResourceCacheUsage() const;      renderthread::RenderThread& mRenderThread; +    SkColorType mSurfaceColorType; +    sk_sp<SkColorSpace> mSurfaceColorSpace;  private:      void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index e34f160467af..a2d811993f2f 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -123,8 +123,7 @@ bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,      }      if (surface) { -        // TODO: handle color mode -        mVkSurface = mVkManager.createSurface(surface); +        mVkSurface = mVkManager.createSurface(surface, colorMode);      }      return mVkSurface != nullptr; @@ -138,14 +137,6 @@ bool SkiaVulkanPipeline::isContextReady() {      return CC_LIKELY(mVkManager.hasVkContext());  } -SkColorType SkiaVulkanPipeline::getSurfaceColorType() const { -    return mVkManager.getSurfaceColorType(); -} - -sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() { -    return mVkManager.getSurfaceColorSpace(); -} -  void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {      VkFunctorDrawable::vkInvokeFunctor(functor);  } diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 6e723a8373e1..14c0d69dba33 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -43,8 +43,6 @@ public:      void onStop() override;      bool isSurfaceReady() override;      bool isContextReady() override; -    SkColorType getSurfaceColorType() const override; -    sk_sp<SkColorSpace> getSurfaceColorSpace() override;      static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);      static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index c8c394a72541..92a749f3da33 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -144,8 +144,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {      mNativeSurface = std::move(surface); -    // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode. -    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy; +    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;      bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);      mFrameNumber = -1; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2315cb9c73f9..2307ee4801d3 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -182,6 +182,23 @@ public:          mFrameCompleteCallbacks.push_back(std::move(func));      } +    void setForceDark(bool enable) { +        mUseForceDark = enable; +    } + +    bool useForceDark() { +        // The force-dark override has the highest priority, followed by the disable setting +        // for the feature as a whole, followed last by whether or not this context has had +        // force dark set (typically automatically done via UIMode) +        if (Properties::forceDarkMode) { +            return true; +        } +        if (!Properties::enableForceDarkSupport) { +            return false; +        } +        return mUseForceDark; +    } +  private:      CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,                    IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); @@ -228,6 +245,7 @@ private:      bool mOpaque;      bool mWideColorGamut = false; +    bool mUseForceDark = false;      LightInfo mLightInfo;      LightGeometry mLightGeometry = {{0, 0, 0}, 0}; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 0cb23e532064..d4ffddde8def 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -126,17 +126,6 @@ void EglManager::initialize() {      createContext();      createPBufferSurface();      makeCurrent(mPBufferSurface, nullptr, /* force */ true); - -    mSurfaceColorGamut = DataSpaceToColorGamut( -        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace())); - -    LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut && -                        !EglExtensions.displayP3, "EGL doesn't support Display P3."); - -    mSurfaceColorType = PixelFormatToColorType( -        static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat())); -    mSurfaceColorSpace = DataSpaceToColorSpace( -        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));  }  void EglManager::initExtensions() { @@ -309,21 +298,13 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode color          if (wideColorGamut) {              attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;          } else { -            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { -                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; -            } else { -                attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; -            } +            attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;          }  #else          if (wideColorGamut) {              attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;          } else { -            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { -                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; -            } else { -                attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; -            } +            attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;          }  #endif      } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index e97228cd0a39..55c81d42d8a0 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -78,9 +78,6 @@ public:      // Depending on installed extensions, the result is either Android native fence or EGL fence.      status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence); -    SkColorType getSurfaceColorType() const { return mSurfaceColorType; } -    sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; } -  private:      void initExtensions(); @@ -95,9 +92,6 @@ private:      EGLContext mEglContext;      EGLSurface mPBufferSurface;      EGLSurface mCurrentSurface; -    SkColorSpace::Gamut mSurfaceColorGamut; -    SkColorType mSurfaceColorType; -    sk_sp<SkColorSpace> mSurfaceColorSpace;      enum class SwapBehavior {          Discard, diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 0297c9c141ff..4972554c65cc 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -43,15 +43,8 @@ namespace renderthread {  enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };  enum class ColorMode { -    // Legacy means HWUI will produce buffer with whatever platform prefers -    // HWUI to produce, however, HWUI doesn't accurately convert color from -    // source color space to destination color space, instead HWUI will take -    // the pixel value directly and interpret it destination color space. -    Legacy, -    // DisplayColorGamut means HWUI will produce buffer with whatever platform -    // prefers HWUI to produce and accurately convert color from source color -    // space to destination color space. -    DisplayColorGamut, +    // SRGB means HWUI will produce buffer in SRGB color space. +    SRGB,      // WideColorGamut means HWUI would support rendering scRGB non-linear into      // a signed buffer with enough range to support the wide color gamut of the      // display. diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 6106e24c093b..54219b5a1489 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -298,6 +298,12 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr)      });  } +void RenderProxy::setForceDark(bool enable) { +    mRenderThread.queue().post([this, enable]() { +        mContext->setForceDark(enable); +    }); +} +  int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,                                   SkBitmap* bitmap) {      auto& thread = RenderThread::getInstance(); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index d22f56ef38fd..d29fcc49d7a6 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -119,7 +119,7 @@ public:      ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);      ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer); -    ANDROID_API long getDroppedFrameReportCount(); +    ANDROID_API void setForceDark(bool enable);      ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,                                             int bottom, SkBitmap* bitmap); diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 285a1a5f4540..83e9db359356 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -618,7 +618,8 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt          VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];          imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(                  mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin, -                kRGBA_8888_SkColorType, nullptr, &props); +                surface->mColorMode == ColorMode::WideColorGamut ? kRGBA_F16_SkColorType +                : kRGBA_8888_SkColorType, nullptr, &props);      }      SkASSERT(mCommandPool != VK_NULL_HANDLE); @@ -733,24 +734,22 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {                      ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR                      : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; -    // Pick our surface format. For now, just make sure it matches our sRGB request: -    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; +    VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;      VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - -    bool wantSRGB = false; -#ifdef ANDROID_ENABLE_LINEAR_BLENDING -    wantSRGB = true; -#endif +    if (surface->mColorMode == ColorMode::WideColorGamut) { +        surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT; +        colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT; +    } +    bool foundSurfaceFormat = false;      for (uint32_t i = 0; i < surfaceFormatCount; ++i) { -        // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB -        VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; -        if (desiredFormat == surfaceFormats[i].format) { -            surfaceFormat = surfaceFormats[i].format; -            colorSpace = surfaceFormats[i].colorSpace; +        if (surfaceFormat == surfaceFormats[i].format +                && colorSpace == surfaceFormats[i].colorSpace) { +            foundSurfaceFormat = true; +            break;          }      } -    if (VK_FORMAT_UNDEFINED == surfaceFormat) { +    if (!foundSurfaceFormat) {          return false;      } @@ -812,14 +811,14 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {      return true;  } -VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) { +VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode) {      initialize();      if (!window) {          return nullptr;      } -    VulkanSurface* surface = new VulkanSurface(); +    VulkanSurface* surface = new VulkanSurface(colorMode);      VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;      memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index c211f5d2b5d7..7c59b6d340d2 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -26,6 +26,7 @@  #include <ui/Fence.h>  #include <utils/StrongPointer.h>  #include <vk/GrVkBackendContext.h> +#include "IRenderPipeline.h"  class GrVkExtensions; @@ -37,7 +38,7 @@ class RenderThread;  class VulkanSurface {  public: -    VulkanSurface() {} +    VulkanSurface(ColorMode colorMode) : mColorMode(colorMode) {}      sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; } @@ -73,6 +74,7 @@ private:      VkImage* mImages = nullptr;      ImageInfo* mImageInfos;      uint16_t mCurrentTime = 0; +    ColorMode mColorMode;  };  // This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue, @@ -90,7 +92,7 @@ public:      // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new      // VulkanSurface object which is returned. -    VulkanSurface* createSurface(ANativeWindow* window); +    VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode);      // Destroy the VulkanSurface and all associated vulkan objects.      void destroySurface(VulkanSurface* surface); @@ -118,10 +120,6 @@ public:      // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.      status_t createReleaseFence(sp<Fence>& nativeFence); -    // TODO(b/115636873): Handle composition preference. -    SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; } -    sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); } -  private:      friend class RenderThread; diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 680fcb3a732b..cdf31da37074 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -386,7 +386,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {  RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {      auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);      EXPECT_FALSE(pipeline->isSurfaceReady()); -    EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy)); +    EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB));      EXPECT_TRUE(pipeline->isSurfaceReady());      renderThread.destroyGlContext();      EXPECT_FALSE(pipeline->isSurfaceReady()); diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 9f71e91629fb..3fb6a31a7d97 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -57,21 +57,6 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {      return false;  } -SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) { -    switch (pixelFormat) { -        case HAL_PIXEL_FORMAT_RGBA_8888: -        case HAL_PIXEL_FORMAT_BGRA_8888: -            return SkColorType::kN32_SkColorType; -        case HAL_PIXEL_FORMAT_RGBA_FP16: -            return SkColorType::kRGBA_F16_SkColorType; -        case HAL_PIXEL_FORMAT_RGBA_1010102: -            return SkColorType::kRGBA_1010102_SkColorType; -        default: -            ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat); -            return SkColorType::kN32_SkColorType; -    } -} -  android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {      switch (colorType) {          case kRGBA_8888_SkColorType: @@ -92,30 +77,6 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {      }  } -SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) { -    switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) { -        case HAL_DATASPACE_STANDARD_BT709: -            return SkColorSpace::kSRGB_Gamut; -        case HAL_DATASPACE_STANDARD_BT2020: -            return SkColorSpace::kRec2020_Gamut; -        case HAL_DATASPACE_STANDARD_DCI_P3: -            return SkColorSpace::kDCIP3_D65_Gamut; -        case HAL_DATASPACE_STANDARD_ADOBE_RGB: -            return SkColorSpace::kAdobeRGB_Gamut; -        case HAL_DATASPACE_STANDARD_UNSPECIFIED: -        case HAL_DATASPACE_STANDARD_BT601_625: -        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: -        case HAL_DATASPACE_STANDARD_BT601_525: -        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: -        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE: -        case HAL_DATASPACE_STANDARD_BT470M: -        case HAL_DATASPACE_STANDARD_FILM: -        default: -            ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace); -            return SkColorSpace::kSRGB_Gamut; -    } -} -  sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {      SkColorSpace::Gamut gamut; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index e935a0d5ec8b..4daccda78e23 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -115,12 +115,8 @@ static constexpr float EOCF(float srgb) {  // returns true for sRGB, gamma 2.2 and Display P3 for instance  bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); -SkColorType PixelFormatToColorType(android_pixel_format pixelFormat); -  android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); -SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace); -  sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);  struct Lab { diff --git a/location/lib/Android.bp b/location/lib/Android.bp index 447195d6d532..b09335c6707f 100644 --- a/location/lib/Android.bp +++ b/location/lib/Android.bp @@ -18,4 +18,5 @@ java_sdk_library {      name: "com.android.location.provider",      srcs: ["java/**/*.java"],      api_packages: ["com.android.location.provider"], +    metalava_enabled: false,  } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index ed4da22f69e7..340f27950638 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -336,7 +336,7 @@ import java.util.Vector;   *   * <table border="0" cellspacing="0" cellpadding="0">   * <tr><td>Method Name </p></td> - *     <td>Valid Sates </p></td> + *     <td>Valid States </p></td>   *     <td>Invalid States </p></td>   *     <td>Comments </p></td></tr>   * <tr><td>attachAuxEffect </p></td> diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index 6b48f09f5fb2..dfcbabeea4f3 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -36,8 +36,6 @@ import android.os.Handler;  import android.os.HandlerThread;  import android.os.Looper;  import android.os.Message; -import android.os.Parcel; -import android.os.Parcelable;  import android.os.PersistableBundle;  import android.os.PowerManager;  import android.os.Process; @@ -60,7 +58,6 @@ import com.android.internal.util.Preconditions;  import dalvik.system.CloseGuard;  import libcore.io.IoBridge; -import libcore.io.Streams;  import java.io.ByteArrayOutputStream;  import java.io.File; @@ -254,22 +251,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {              void process() {                  stayAwake(false); -                // TODO: remove this block when native code allows prepared -> pause -                // and sends MEDIA_INFO_DATA_SOURCE_START when pipeline is created. -                if (getState() == PLAYER_STATE_PREPARED) { -                    final DataSourceDesc dsd; -                    synchronized (mSrcLock) { -                        dsd = mCurrentDSD; -                    } -                    sendEvent(new EventNotifier() { -                        @Override -                        public void notify(EventCallback callback) { -                            callback.onInfo( -                                    MediaPlayer2Impl.this, dsd, MEDIA_INFO_DATA_SOURCE_START, 0); -                        } -                    }); -                } -                  _pause();              }          }); @@ -287,7 +268,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {          addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {              @Override              void process() { -                // TODO: switch to next data source and play +                if (getState() == PLAYER_STATE_PLAYING) { +                    pause(); +                } +                playNextDataSource();              }          });      } @@ -348,19 +332,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {                      final String msg = "Cannot set AudioAttributes to null";                      throw new IllegalArgumentException(msg);                  } -                Parcel pattributes = Parcel.obtain(); -                attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS); -                setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes); -                pattributes.recycle(); +                setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, attributes);              }          });      }      @Override      public @NonNull AudioAttributes getAudioAttributes() { -        Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES); -        AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes); -        pattributes.recycle(); +        AudioAttributes attributes = (AudioAttributes) getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);          return attributes;      } @@ -1601,9 +1580,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {       * @param value value of the parameter to be set.       * @return true if the parameter is set successfully, false otherwise       */ -    private native boolean setParameter(int key, Parcel value); +    private native boolean setParameter(int key, Object value); -    private native Parcel getParameter(int key); +    private native Object getParameter(int key);      /** @@ -3702,7 +3681,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {                        supportedSchemes[i]);              } -            Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + pssh.length + +            Log.v(TAG, "DrmInfoImpl() psshsize: " + pssh.length +                    " supportedDRMsCount: " + supportedDRMsCount);          } @@ -3967,7 +3946,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {                      connection.setReadTimeout(TIMEOUT_MS);                      connection.connect(); -                    response = Streams.readFully(connection.getInputStream()); +                    response = readInputStreamFully(connection.getInputStream());                      Log.v(TAG, "HandleProvisioninig: Thread run: response " +                              response.length + " " + response); @@ -4047,6 +4026,29 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {              finished = true;          }   // run() +        /** +         * Returns a byte[] containing the remainder of 'in', closing it when done. +         */ +        private byte[] readInputStreamFully(InputStream in) throws IOException { +            try { +                return readInputStreamFullyNoClose(in); +            } finally { +                in.close(); +            } +        } + +        /** +         * Returns a byte[] containing the remainder of 'in'. +         */ +        private byte[] readInputStreamFullyNoClose(InputStream in) throws IOException { +            ByteArrayOutputStream bytes = new ByteArrayOutputStream(); +            byte[] buffer = new byte[1024]; +            int count; +            while ((count = in.read(buffer)) != -1) { +                bytes.write(buffer, 0, count); +            } +            return bytes.toByteArray(); +        }      }   // ProvisioningThread      private int HandleProvisioninig(UUID uuid) { diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 0ff2d8f6b6ec..c537945624fe 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -160,8 +160,9 @@ public class MediaScanner implements AutoCloseable {      public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";      public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint"; -    private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio"; -    private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio"; +    private static final String SYSTEM_SOUNDS_DIR = Environment.getRootDirectory() + "/media/audio"; +    private static final String OEM_SOUNDS_DIR = Environment.getOemDirectory() + "/media/audio"; +    private static final String PRODUCT_SOUNDS_DIR = Environment.getProductDirectory() + "/media/audio";      private static String sLastInternalScanFingerprint;      private static final String[] ID3_GENRES = { @@ -1193,6 +1194,9 @@ public class MediaScanner implements AutoCloseable {          if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)                  || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)                  || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR) +                || path.startsWith(OEM_SOUNDS_DIR + ALARMS_DIR) +                || path.startsWith(OEM_SOUNDS_DIR + RINGTONES_DIR) +                || path.startsWith(OEM_SOUNDS_DIR + NOTIFICATIONS_DIR)                  || path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR)                  || path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR)                  || path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) { diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 1a844cc678c6..693a3d0b23df 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -1490,8 +1490,8 @@ static const JNINativeMethod gMethods[] = {      {"_release",            "()V",                              (void *)android_media_MediaPlayer2_release},      {"_reset",              "()V",                              (void *)android_media_MediaPlayer2_reset},      {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer2_getAudioStreamType}, -    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer2_setParameter}, -    {"getParameter",        "(I)Landroid/os/Parcel;",           (void *)android_media_MediaPlayer2_getParameter}, +    {"setParameter",        "(ILjava/lang/Object;)Z",          (void *)android_media_MediaPlayer2_setParameter}, +    {"getParameter",        "(I)Ljava/lang/Object;",           (void *)android_media_MediaPlayer2_getParameter},      {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer2_setLooping},      {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer2_isLooping},      {"_setVolume",          "(FF)V",                            (void *)android_media_MediaPlayer2_setVolume}, diff --git a/media/lib/remotedisplay/Android.bp b/media/lib/remotedisplay/Android.bp index 1e9320d1414d..5f4b930f350e 100644 --- a/media/lib/remotedisplay/Android.bp +++ b/media/lib/remotedisplay/Android.bp @@ -14,22 +14,8 @@  // limitations under the License.  // -droiddoc { -    name: "com.android.media.remotedisplay.stubs-gen-docs", -    srcs: [ -        "java/**/*.java", -    ], -    args: " -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " + -          " -stubpackages com.android.media.remotedisplay " + -          " -nodocs ", -    custom_template: "droiddoc-templates-sdk", -    installable: false, -} - -java_library_static { -    name: "com.android.media.remotedisplay.stubs", -    srcs: [ -        ":com.android.media.remotedisplay.stubs-gen-docs", -    ], -    sdk_version: "current", +java_sdk_library { +    name: "com.android.media.remotedisplay", +    srcs: ["java/**/*.java"], +    api_packages: ["com.android.media.remotedisplay"],  } diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk deleted file mode 100644 index e88c0f1a8dc8..000000000000 --- a/media/lib/remotedisplay/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (C) 2013 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. -# -LOCAL_PATH := $(call my-dir) - -# the remotedisplay library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_MODULE:= com.android.media.remotedisplay -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := $(call all-java-files-under, java) - -include $(BUILD_JAVA_LIBRARY) - - -# ====  com.android.media.remotedisplay.xml lib def  ======================== -include $(CLEAR_VARS) - -LOCAL_MODULE := com.android.media.remotedisplay.xml -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE_CLASS := ETC - -# This will install the file in /system/etc/permissions -# -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions - -LOCAL_SRC_FILES := $(LOCAL_MODULE) - -include $(BUILD_PREBUILT) diff --git a/media/lib/remotedisplay/OWNERS b/media/lib/remotedisplay/OWNERS new file mode 100644 index 000000000000..7e7335d68d3b --- /dev/null +++ b/media/lib/remotedisplay/OWNERS @@ -0,0 +1 @@ +michaelwr@google.com diff --git a/media/lib/remotedisplay/api/current.txt b/media/lib/remotedisplay/api/current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/media/lib/remotedisplay/api/current.txt diff --git a/media/lib/remotedisplay/api/removed.txt b/media/lib/remotedisplay/api/removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/media/lib/remotedisplay/api/removed.txt diff --git a/media/lib/remotedisplay/api/system-current.txt b/media/lib/remotedisplay/api/system-current.txt new file mode 100644 index 000000000000..69bbd35fce59 --- /dev/null +++ b/media/lib/remotedisplay/api/system-current.txt @@ -0,0 +1,52 @@ +package com.android.media.remotedisplay { + +  public class RemoteDisplay { +    ctor public RemoteDisplay(java.lang.String, java.lang.String); +    method public java.lang.String getDescription(); +    method public java.lang.String getId(); +    method public java.lang.String getName(); +    method public int getPresentationDisplayId(); +    method public int getStatus(); +    method public int getVolume(); +    method public int getVolumeHandling(); +    method public int getVolumeMax(); +    method public void setDescription(java.lang.String); +    method public void setName(java.lang.String); +    method public void setPresentationDisplayId(int); +    method public void setStatus(int); +    method public void setVolume(int); +    method public void setVolumeHandling(int); +    method public void setVolumeMax(int); +    field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0 +    field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1 +    field public static final int STATUS_AVAILABLE = 2; // 0x2 +    field public static final int STATUS_CONNECTED = 4; // 0x4 +    field public static final int STATUS_CONNECTING = 3; // 0x3 +    field public static final int STATUS_IN_USE = 1; // 0x1 +    field public static final int STATUS_NOT_AVAILABLE = 0; // 0x0 +  } + +  public abstract class RemoteDisplayProvider { +    ctor public RemoteDisplayProvider(android.content.Context); +    method public void addDisplay(com.android.media.remotedisplay.RemoteDisplay); +    method public com.android.media.remotedisplay.RemoteDisplay findRemoteDisplay(java.lang.String); +    method public android.os.IBinder getBinder(); +    method public final android.content.Context getContext(); +    method public int getDiscoveryMode(); +    method public java.util.Collection<com.android.media.remotedisplay.RemoteDisplay> getDisplays(); +    method public android.app.PendingIntent getSettingsPendingIntent(); +    method public void onAdjustVolume(com.android.media.remotedisplay.RemoteDisplay, int); +    method public void onConnect(com.android.media.remotedisplay.RemoteDisplay); +    method public void onDisconnect(com.android.media.remotedisplay.RemoteDisplay); +    method public void onDiscoveryModeChanged(int); +    method public void onSetVolume(com.android.media.remotedisplay.RemoteDisplay, int); +    method public void removeDisplay(com.android.media.remotedisplay.RemoteDisplay); +    method public void updateDisplay(com.android.media.remotedisplay.RemoteDisplay); +    field public static final int DISCOVERY_MODE_ACTIVE = 2; // 0x2 +    field public static final int DISCOVERY_MODE_NONE = 0; // 0x0 +    field public static final int DISCOVERY_MODE_PASSIVE = 1; // 0x1 +    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.remotedisplay.RemoteDisplayProvider"; +  } + +} + diff --git a/media/lib/remotedisplay/api/system-removed.txt b/media/lib/remotedisplay/api/system-removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/media/lib/remotedisplay/api/system-removed.txt diff --git a/media/lib/remotedisplay/api/test-current.txt b/media/lib/remotedisplay/api/test-current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/media/lib/remotedisplay/api/test-current.txt diff --git a/media/lib/remotedisplay/api/test-removed.txt b/media/lib/remotedisplay/api/test-removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/media/lib/remotedisplay/api/test-removed.txt diff --git a/media/lib/remotedisplay/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml deleted file mode 100644 index 77a91d23e1d8..000000000000 --- a/media/lib/remotedisplay/com.android.media.remotedisplay.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> - -<permissions> -    <library name="com.android.media.remotedisplay" -            file="/system/framework/com.android.media.remotedisplay.jar" /> -</permissions> diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java index dc9dd79eb2b1..8de414b45a4d 100644 --- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java +++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java @@ -16,6 +16,7 @@  package com.android.media.remotedisplay; +import android.annotation.SystemApi;  import android.media.RemoteDisplayState.RemoteDisplayInfo;  import android.text.TextUtils; @@ -23,7 +24,10 @@ import java.util.Objects;  /**   * Represents a remote display that has been discovered. + * + * @hide   */ +@SystemApi  public class RemoteDisplay {      private final RemoteDisplayInfo mMutableInfo;      private RemoteDisplayInfo mImmutableInfo; diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java index 4d3edb896eb5..7017e444d717 100644 --- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java +++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java @@ -16,6 +16,7 @@  package com.android.media.remotedisplay; +import android.annotation.SystemApi;  import android.app.PendingIntent;  import android.app.Service;  import android.content.Context; @@ -88,7 +89,10 @@ import java.util.Collection;   * IMPORTANT: This class is effectively a public API for unbundled applications, and   * must remain API stable. See README.txt in the root of this package for more information.   * </p> + * + * @hide   */ +@SystemApi  public abstract class RemoteDisplayProvider {      private static final int MSG_SET_CALLBACK = 1;      private static final int MSG_SET_DISCOVERY_MODE = 2; diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp index 3b2578754087..8c43683c2eec 100644 --- a/media/lib/signer/Android.bp +++ b/media/lib/signer/Android.bp @@ -18,4 +18,5 @@ java_sdk_library {      name: "com.android.mediadrm.signer",      srcs: ["java/**/*.java"],      api_packages: ["com.android.mediadrm.signer"], +    metalava_enabled: false,  } diff --git a/packages/LocalTransport/Android.mk b/packages/LocalTransport/Android.mk new file mode 100644 index 000000000000..3484b0f7a537 --- /dev/null +++ b/packages/LocalTransport/Android.mk @@ -0,0 +1,35 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_PACKAGE_NAME := LocalTransport +LOCAL_PRIVATE_PLATFORM_APIS := true +LOCAL_CERTIFICATE := platform +LOCAL_PRIVILEGED_MODULE := true + +include $(BUILD_PACKAGE) + +######################## +include $(call all-makefiles-under,$(LOCAL_PATH)) + diff --git a/packages/LocalTransport/AndroidManifest.xml b/packages/LocalTransport/AndroidManifest.xml new file mode 100644 index 000000000000..196be1e998f3 --- /dev/null +++ b/packages/LocalTransport/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (c) 2018 Google Inc. + * + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +      package="com.android.localtransport" +      android:sharedUserId="android.uid.system" > + + +    <application android:allowBackup="false" > +        <!-- This service does not need to be exported because it shares uid with the system server +        which is the only client. --> +        <service android:name=".LocalTransportService" +                 android:permission="android.permission.CONFIRM_FULL_BACKUP" +                 android:exported="false"> +            <intent-filter> +                <action android:name="android.backup.TRANSPORT_HOST" /> +            </intent-filter> +        </service> + +    </application> +</manifest> diff --git a/packages/LocalTransport/proguard.flags b/packages/LocalTransport/proguard.flags new file mode 100644 index 000000000000..c1f51b892d40 --- /dev/null +++ b/packages/LocalTransport/proguard.flags @@ -0,0 +1,5 @@ +-keep class com.android.localTransport.LocalTransport +-keep class com.android.localTransport.LocalTransportParameters +-keep class com.android.localTransport.LocalTransportService + + diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java index d0f02725b1a0..0bf8bc1051c2 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package com.android.internal.backup; +package com.android.localtransport;  import android.app.backup.BackupAgent;  import android.app.backup.BackupDataInput; @@ -26,7 +26,6 @@ import android.content.ComponentName;  import android.content.Context;  import android.content.Intent;  import android.content.pm.PackageInfo; -import android.os.Environment;  import android.os.ParcelFileDescriptor;  import android.system.ErrnoException;  import android.system.Os; @@ -56,7 +55,7 @@ public class LocalTransport extends BackupTransport {      private static final boolean DEBUG = false;      private static final String TRANSPORT_DIR_NAME -            = "com.android.internal.backup.LocalTransport"; +            = "com.android.localtransport.LocalTransport";      private static final String TRANSPORT_DESTINATION_STRING              = "Backing up to debug-only private cache"; @@ -75,10 +74,10 @@ public class LocalTransport extends BackupTransport {      private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;      private Context mContext; -    private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); -    private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN)); -    private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR); -    private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR); +    private File mDataDir; +    private File mCurrentSetDir; +    private File mCurrentSetIncrementalDir; +    private File mCurrentSetFullDir;      private PackageInfo[] mRestorePackages = null;      private int mRestorePackage = -1;  // Index into mRestorePackages @@ -101,6 +100,11 @@ public class LocalTransport extends BackupTransport {      private final LocalTransportParameters mParameters;      private void makeDataDirs() { +        mDataDir = mContext.getFilesDir(); +        mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN)); +        mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR); +        mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR); +          mCurrentSetDir.mkdirs();          mCurrentSetFullDir.mkdir();          mCurrentSetIncrementalDir.mkdir(); diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java index 2427d39fd65e..784be224f367 100644 --- a/core/java/com/android/internal/backup/LocalTransportParameters.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java @@ -14,7 +14,7 @@   * limitations under the License   */ -package com.android.internal.backup; +package com.android.localtransport;  import android.util.KeyValueSettingObserver;  import android.content.ContentResolver; diff --git a/core/java/com/android/internal/backup/LocalTransportService.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java index 69c48e2a48cf..ac4f418b68f6 100644 --- a/core/java/com/android/internal/backup/LocalTransportService.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package com.android.internal.backup; +package com.android.localtransport;  import android.app.Service;  import android.content.Intent; diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index 580308a4cffd..8c29a2520390 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -430,9 +430,14 @@ public class PackageInstallerActivity extends AlertActivity {              // Check for unknown sources restriction              final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(                      UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle()); -            if ((unknownSourcesRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { +            final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource( +                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle()); +            final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM +                    & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource); +            if (systemRestriction != 0) {                  showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER); -            } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) { +            } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET +                    || unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {                  startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));                  finish();              } else { diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index ee4c95445bff..89438e555b0d 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -15,6 +15,7 @@ android_library {          "SettingsLibHelpUtils",          "SettingsLibRestrictedLockUtils",          "SettingsLibAppPreference", +        "SettingsLibSearchWidget",      ],      // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES diff --git a/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml index a034d297bac8..2f576e62202e 100644 --- a/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml @@ -17,5 +17,5 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> -    <string name="help_feedback_label" msgid="4550436169116444686">"Help en feedback"</string> +    <string name="help_feedback_label" msgid="4550436169116444686">"Hulp en feedback"</string>  </resources> diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp new file mode 100644 index 000000000000..7541ca456138 --- /dev/null +++ b/packages/SettingsLib/SearchWidget/Android.bp @@ -0,0 +1,8 @@ +android_library { +    name: "SettingsLibSearchWidget", + +    srcs: ["src/**/*.java"], +    resource_dirs: ["res"], +    sdk_version: "system_current", +    min_sdk_version: "21", +} diff --git a/packages/SettingsLib/SearchWidget/AndroidManifest.xml b/packages/SettingsLib/SearchWidget/AndroidManifest.xml new file mode 100644 index 000000000000..b86544ec68c1 --- /dev/null +++ b/packages/SettingsLib/SearchWidget/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  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. +  --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +          package="com.android.settingslib.search"> + +    <uses-sdk android:minSdkVersion="21" /> + +</manifest> diff --git a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml new file mode 100644 index 000000000000..7e65848de189 --- /dev/null +++ b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  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. +  --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" +        android:width="24dp" +        android:height="24dp" +        android:viewportWidth="24" +        android:viewportHeight="24" +        android:tint="?android:attr/colorControlNormal"> +    <path +        android:fillColor="#FF000000" +        android:pathData="M20.49,19l-5.73,-5.73C15.53,12.2 16,10.91 16,9.5C16,5.91 13.09,3 9.5,3S3,5.91 3,9.5C3,13.09 5.91,16 9.5,16c1.41,0 2.7,-0.47 3.77,-1.24L19,20.49L20.49,19zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/> +</vector> diff --git a/packages/SettingsLib/SearchWidget/res/values/strings.xml b/packages/SettingsLib/SearchWidget/res/values/strings.xml new file mode 100644 index 000000000000..0b12810ffc38 --- /dev/null +++ b/packages/SettingsLib/SearchWidget/res/values/strings.xml @@ -0,0 +1,20 @@ +<!-- +  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. +  --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +    <!-- Text used as a search hint into the search box [CHAR_LIMIT=60]--> +    <string name="search_menu">Search settings</string> +</resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 3859092ebfa8..bd9a6ec335b7 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -446,7 +446,6 @@      <string name="alarm_template_far" msgid="3779172822607461675">"अलार्म <xliff:g id="WHEN">%1$s</xliff:g> को बजेगा"</string>      <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"अवधि"</string>      <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string> -    <!-- no translation found for zen_mode_forever (2704305038191592967) --> -    <skip /> +    <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>      <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>  </resources> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 332ced66ef77..508adbd2a121 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1116,4 +1116,6 @@      <!-- time label for event have that happened very recently [CHAR LIMIT=60] -->      <string name="time_unit_just_now">Just now</string> -  </resources> +    <!-- The notice header of Third-party licenses. not translatable --> +    <string name="notice_header" translatable="false"></string> +</resources> diff --git a/packages/SettingsLib/search/Android.mk b/packages/SettingsLib/search/Android.mk index cb1989157db8..14f96269c54e 100644 --- a/packages/SettingsLib/search/Android.mk +++ b/packages/SettingsLib/search/Android.mk @@ -5,6 +5,9 @@ LOCAL_MODULE = SettingsLib-search  LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_RESOURCE_DIR := \ +    $(LOCAL_PATH)/main/res +  include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index a71041045df2..58feef55bd29 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -102,7 +102,7 @@ public class A2dpProfile implements LocalBluetoothProfile {                  BluetoothProfile.A2DP);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java index e13e566ec901..988062de0a37 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java @@ -96,7 +96,7 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {                  BluetoothProfile.A2DP_SINK);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index ecaeaf21f24c..750a8438c00d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -34,7 +34,6 @@ import com.android.settingslib.R;  import java.util.ArrayList;  import java.util.Collection;  import java.util.Collections; -import java.util.HashMap;  import java.util.List;  import androidx.annotation.VisibleForTesting; @@ -59,7 +58,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>      private long mHiSyncId;      // Need this since there is no method for getting RSSI      private short mRssi; -    private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;      private final List<LocalBluetoothProfile> mProfiles =              new ArrayList<LocalBluetoothProfile>(); @@ -101,7 +99,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>          mLocalAdapter = BluetoothAdapter.getDefaultAdapter();          mProfileManager = profileManager;          mDevice = device; -        mProfileConnectionState = new HashMap<>();          fillData();          mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;      } @@ -134,7 +131,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>              }              return;          } -        mProfileConnectionState.put(profile, newProfileState);          if (newProfileState == BluetoothProfile.STATE_CONNECTED) {              if (profile instanceof MapProfile) {                  profile.setPreferred(mDevice, true); @@ -226,7 +222,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>          int preferredProfiles = 0;          for (LocalBluetoothProfile profile : mProfiles) { -            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) { +            if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) {                  if (profile.isPreferred(mDevice)) {                      ++preferredProfiles;                      connectInt(profile); @@ -324,22 +320,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>      }      public int getProfileConnectionState(LocalBluetoothProfile profile) { -        if (mProfileConnectionState.get(profile) == null) { -            // If cache is empty make the binder call to get the state -            int state = profile.getConnectionStatus(mDevice); -            mProfileConnectionState.put(profile, state); -        } -        return mProfileConnectionState.get(profile); -    } - -    public void clearProfileConnectionState () -    { -        if (BluetoothUtils.D) { -            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName()); -        } -        for (LocalBluetoothProfile profile :getProfiles()) { -            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED); -        } +        return profile != null +                ? profile.getConnectionStatus(mDevice) +                : BluetoothProfile.STATE_DISCONNECTED;      }      // TODO: do any of these need to run async on a background thread? @@ -661,7 +644,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>          List<LocalBluetoothProfile> connectableProfiles =                  new ArrayList<LocalBluetoothProfile>();          for (LocalBluetoothProfile profile : mProfiles) { -            if (profile.isConnectable()) { +            if (profile.accessProfileEnabled()) {                  connectableProfiles.add(profile);              }          } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 5a64e02cece4..21cf0c27a8d5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -285,11 +285,6 @@ public class CachedBluetoothDeviceManager {                      {                          mCachedDevicesMapForHearingAids.remove(cachedDevice.getHiSyncId());                      } -                } else { -                    // For bonded devices, we need to clear the connection status so that -                    // when BT is enabled next time, device connection status shall be retrieved -                    // by making a binder call. -                    cachedDevice.clearProfileConnectionState();                  }              }              for (int i = mHearingAidDevicesNotAddedInCache.size() - 1; i >= 0; i--) { @@ -297,11 +292,6 @@ public class CachedBluetoothDeviceManager {                  if (notCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {                      notCachedDevice.setJustDiscovered(false);                      mHearingAidDevicesNotAddedInCache.remove(i); -                } else { -                    // For bonded devices, we need to clear the connection status so that -                    // when BT is enabled next time, device connection status shall be retrieved -                    // by making a binder call. -                    notCachedDevice.clearProfileConnectionState();                  }              }          } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 2dd8eaf7021d..62507f58426f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -103,7 +103,7 @@ public class HeadsetProfile implements LocalBluetoothProfile {                  BluetoothProfile.HEADSET);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index 1eeb4f058d1d..8bc0acf5f824 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -100,7 +100,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {                  new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return false;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java index 4b6a22c9b2c8..4879144a5994 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java @@ -104,7 +104,7 @@ final class HfpClientProfile implements LocalBluetoothProfile {      }      @Override -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java index c8d4fc84f4b4..61e5b6b3e125 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java @@ -94,7 +94,7 @@ public class HidDeviceProfile implements LocalBluetoothProfile {      }      @Override -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java index fe6b22224819..75d16db13efe 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java @@ -93,7 +93,7 @@ public class HidProfile implements LocalBluetoothProfile {                  BluetoothProfile.HID_HOST);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java index 0447f378fca1..4b0ca7434f9a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java @@ -26,9 +26,9 @@ import android.bluetooth.BluetoothDevice;  public interface LocalBluetoothProfile {      /** -     * Returns true if the user can initiate a connection, false otherwise. +     * Return {@code true} if the user can initiate a connection for this profile in UI.       */ -    boolean isConnectable(); +    boolean accessProfileEnabled();      /**       * Returns true if the user can enable auto connection for this profile. diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 7000f9d7a7d2..9653972414ee 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -30,6 +30,7 @@ import android.bluetooth.BluetoothMapClient;  import android.bluetooth.BluetoothPan;  import android.bluetooth.BluetoothPbap;  import android.bluetooth.BluetoothPbapClient; +import android.bluetooth.BluetoothSap;  import android.bluetooth.BluetoothProfile;  import android.bluetooth.BluetoothUuid;  import android.content.Context; @@ -98,6 +99,7 @@ public class LocalBluetoothProfileManager {      private PbapClientProfile mPbapClientProfile;      private PbapServerProfile mPbapProfile;      private HearingAidProfile mHearingAidProfile; +    private SapProfile mSapProfile;      /**       * Mapping from profile name, e.g. "HEADSET" to profile object. @@ -210,6 +212,13 @@ public class LocalBluetoothProfileManager {              addProfile(mPbapClientProfile, PbapClientProfile.NAME,                      BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);          } +        if (mSapProfile == null && supportedList.contains(BluetoothProfile.SAP)) { +            if (DEBUG) { +                Log.d(TAG, "Adding local SAP profile"); +            } +            mSapProfile = new SapProfile(mContext, mDeviceManager, this); +            addProfile(mSapProfile, SapProfile.NAME, BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); +        }          mEventManager.registerProfileIntentReceiver();      } @@ -290,10 +299,11 @@ public class LocalBluetoothProfileManager {                  }              } -            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState, -                    mProfile.getProfileId());              cachedDevice.onProfileStateChanged(mProfile, newState);              cachedDevice.refresh(); +            // Dispatch profile changed after device update +            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState, +                    mProfile.getProfileId());          }      } @@ -549,6 +559,11 @@ public class LocalBluetoothProfileManager {              removedProfiles.remove(mHearingAidProfile);          } +        if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) { +            profiles.add(mSapProfile); +            removedProfiles.remove(mSapProfile); +        } +          if (DEBUG) {              Log.d(TAG,"New Profiles" + profiles.toString());          } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java index 7ad2e28c84b5..1e22f440b5f8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java @@ -105,7 +105,7 @@ public final class MapClientProfile implements LocalBluetoothProfile {                  new MapClientServiceListener(), BluetoothProfile.MAP_CLIENT);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java index caea04f87a50..758202412c93 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java @@ -104,7 +104,7 @@ public class MapProfile implements LocalBluetoothProfile {                  BluetoothProfile.MAP);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java index dfd16224ef8f..e1e5dbe29a1a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java @@ -32,7 +32,7 @@ final class OppProfile implements LocalBluetoothProfile {      // Order of this profile in device profiles list      private static final int ORDINAL = 2; -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return false;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java index 02afe8db7201..7b811624a6f3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java @@ -78,7 +78,7 @@ public class PanProfile implements LocalBluetoothProfile {              BluetoothProfile.PAN);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java index 8fefb2fc01b8..1f15601f2756 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java @@ -107,7 +107,7 @@ public final class PbapClientProfile implements LocalBluetoothProfile {                  new PbapClientServiceListener(), BluetoothProfile.PBAP_CLIENT);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java index e9d8cb5a4b2b..adef0841cb2a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java @@ -80,7 +80,7 @@ public class PbapServerProfile implements LocalBluetoothProfile {          BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java index 61602c6463ee..b4acc4810faf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -36,12 +36,10 @@ import java.util.List;   */  final class SapProfile implements LocalBluetoothProfile {      private static final String TAG = "SapProfile"; -    private static boolean V = true;      private BluetoothSap mService;      private boolean mIsProfileReady; -    private final LocalBluetoothAdapter mLocalAdapter;      private final CachedBluetoothDeviceManager mDeviceManager;      private final LocalBluetoothProfileManager mProfileManager; @@ -59,7 +57,7 @@ final class SapProfile implements LocalBluetoothProfile {              implements BluetoothProfile.ServiceListener {          public void onServiceConnected(int profile, BluetoothProfile proxy) { -            if (V) Log.d(TAG,"Bluetooth service connected"); +            Log.d(TAG, "Bluetooth service connected, profile:" + profile);              mService = (BluetoothSap) proxy;              // We just bound to the service, so refresh the UI for any connected SAP devices.              List<BluetoothDevice> deviceList = mService.getConnectedDevices(); @@ -81,7 +79,7 @@ final class SapProfile implements LocalBluetoothProfile {          }          public void onServiceDisconnected(int profile) { -            if (V) Log.d(TAG,"Bluetooth service disconnected"); +            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);              mProfileManager.callServiceDisconnectedListeners();              mIsProfileReady=false;          } @@ -96,17 +94,15 @@ final class SapProfile implements LocalBluetoothProfile {          return BluetoothProfile.SAP;      } -    SapProfile(Context context, LocalBluetoothAdapter adapter, -            CachedBluetoothDeviceManager deviceManager, +    SapProfile(Context context, CachedBluetoothDeviceManager deviceManager,              LocalBluetoothProfileManager profileManager) { -        mLocalAdapter = adapter;          mDeviceManager = deviceManager;          mProfileManager = profileManager; -        mLocalAdapter.getProfileProxy(context, new SapServiceListener(), +        BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new SapServiceListener(),                  BluetoothProfile.SAP);      } -    public boolean isConnectable() { +    public boolean accessProfileEnabled() {          return true;      } @@ -115,50 +111,47 @@ final class SapProfile implements LocalBluetoothProfile {      }      public boolean connect(BluetoothDevice device) { -        if (mService == null) return false; -        List<BluetoothDevice> sinks = mService.getConnectedDevices(); -        if (sinks != null) { -            for (BluetoothDevice sink : sinks) { -                mService.disconnect(sink); -            } +        if (mService == null) { +            return false;          }          return mService.connect(device);      }      public boolean disconnect(BluetoothDevice device) { -        if (mService == null) return false; -        List<BluetoothDevice> deviceList = mService.getConnectedDevices(); -        if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) { -            if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { -                mService.setPriority(device, BluetoothProfile.PRIORITY_ON); -            } -            return mService.disconnect(device); -        } else { +        if (mService == null) {              return false;          } +        if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { +            mService.setPriority(device, BluetoothProfile.PRIORITY_ON); +        } +        return mService.disconnect(device);      }      public int getConnectionStatus(BluetoothDevice device) { -        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED; -        List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - -        return !deviceList.isEmpty() && deviceList.get(0).equals(device) -                ? mService.getConnectionState(device) -                : BluetoothProfile.STATE_DISCONNECTED; +        if (mService == null) { +            return BluetoothProfile.STATE_DISCONNECTED; +        } +        return mService.getConnectionState(device);      }      public boolean isPreferred(BluetoothDevice device) { -        if (mService == null) return false; +        if (mService == null) { +            return false; +        }          return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;      }      public int getPreferred(BluetoothDevice device) { -        if (mService == null) return BluetoothProfile.PRIORITY_OFF; +        if (mService == null) { +            return BluetoothProfile.PRIORITY_OFF; +        }          return mService.getPriority(device);      }      public void setPreferred(BluetoothDevice device, boolean preferred) { -        if (mService == null) return; +        if (mService == null) { +            return; +        }          if (preferred) {              if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {                  mService.setPriority(device, BluetoothProfile.PRIORITY_ON); @@ -169,7 +162,9 @@ final class SapProfile implements LocalBluetoothProfile {      }      public List<BluetoothDevice> getConnectedDevices() { -        if (mService == null) return new ArrayList<BluetoothDevice>(0); +        if (mService == null) { +            return new ArrayList<BluetoothDevice>(0); +        }          return mService.getDevicesMatchingConnectionStates(                new int[] {BluetoothProfile.STATE_CONNECTED,                           BluetoothProfile.STATE_CONNECTING, @@ -207,11 +202,11 @@ final class SapProfile implements LocalBluetoothProfile {      }      protected void finalize() { -        if (V) Log.d(TAG, "finalize()"); +        Log.d(TAG, "finalize()");          if (mService != null) {              try {                  BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP, -                                                                       mService); +                        mService);                  mService = null;              }catch (Throwable t) {                  Log.w(TAG, "Error cleaning up SAP proxy", t); diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java index 42306f6d46d0..9db4a35c1d78 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java @@ -46,7 +46,7 @@ import java.util.zip.GZIPInputStream;   * TODO: Remove duplicate codes once backward support ends.   */  class LicenseHtmlGeneratorFromXml { -    private static final String TAG = "LicenseHtmlGeneratorFromXml"; +    private static final String TAG = "LicenseGeneratorFromXml";      private static final String TAG_ROOT = "licenses";      private static final String TAG_FILE_NAME = "file-name"; @@ -107,12 +107,13 @@ class LicenseHtmlGeneratorFromXml {          mXmlFiles = xmlFiles;      } -    public static boolean generateHtml(List<File> xmlFiles, File outputFile) { +    public static boolean generateHtml(List<File> xmlFiles, File outputFile, +            String noticeHeader) {          LicenseHtmlGeneratorFromXml genertor = new LicenseHtmlGeneratorFromXml(xmlFiles); -        return genertor.generateHtml(outputFile); +        return genertor.generateHtml(outputFile, noticeHeader);      } -    private boolean generateHtml(File outputFile) { +    private boolean generateHtml(File outputFile, String noticeHeader) {          for (File xmlFile : mXmlFiles) {              parse(xmlFile);          } @@ -125,7 +126,8 @@ class LicenseHtmlGeneratorFromXml {          try {              writer = new PrintWriter(outputFile); -            generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer); +            generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer, +                noticeHeader);              writer.flush();              writer.close(); @@ -239,13 +241,18 @@ class LicenseHtmlGeneratorFromXml {      @VisibleForTesting      static void generateHtml(Map<String, String> fileNameToContentIdMap, -            Map<String, String> contentIdToFileContentMap, PrintWriter writer) { +            Map<String, String> contentIdToFileContentMap, PrintWriter writer, +            String noticeHeader) {          List<String> fileNameList = new ArrayList();          fileNameList.addAll(fileNameToContentIdMap.keySet());          Collections.sort(fileNameList);          writer.println(HTML_HEAD_STRING); +        if (!TextUtils.isEmpty(noticeHeader)) { +            writer.println(noticeHeader); +        } +          int count = 0;          Map<String, Integer> contentIdToOrderMap = new HashMap();          List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList(); diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java index 393006940740..78e807cf1a1c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java @@ -60,7 +60,7 @@ public class LicenseHtmlLoader extends AsyncLoader<File> {          File cachedHtmlFile = getCachedHtmlFile(mContext);          if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile) -                || generateHtmlFile(xmlFiles, cachedHtmlFile)) { +                || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) {              return cachedHtmlFile;          } diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java index 360c19c2b795..ca6248505dc0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java @@ -19,6 +19,7 @@ package com.android.settingslib.license;  import android.content.Context;  import android.util.Log; +import com.android.settingslib.R;  import com.android.settingslib.utils.AsyncLoaderCompat;  import java.io.File; @@ -65,7 +66,7 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> {          File cachedHtmlFile = getCachedHtmlFile(mContext);          if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile) -                || generateHtmlFile(xmlFiles, cachedHtmlFile)) { +                || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) {              return cachedHtmlFile;          } @@ -101,7 +102,8 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> {          return outdated;      } -    static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) { -        return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile); +    static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) { +        return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile, +                context.getString(R.string.notice_header));      }  } diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java index c3241bbd2123..e9c523881373 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java @@ -36,7 +36,13 @@ import com.android.settingslib.AppItem;  /**   * Loader for historical chart data for both network and UID details. + * + * Deprecated in favor of {@link NetworkCycleChartDataLoader} and + * {@link NetworkCycleDataForUidLoader} + * + * @deprecated   */ +@Deprecated  public class ChartDataLoaderCompat extends AsyncTaskLoader<ChartData> {      private static final String KEY_TEMPLATE = "template";      private static final String KEY_APP = "app"; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java new file mode 100644 index 000000000000..9b3ff8b2e165 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Usage data in a billing cycle with bucketized data for plotting the usage chart. + */ +public class NetworkCycleChartData extends NetworkCycleData { +    public static final long BUCKET_DURATION_MS = TimeUnit.DAYS.toMillis(1); + +    private List<NetworkCycleData> mUsageBuckets; + +    private NetworkCycleChartData() { +    } + +    public List<NetworkCycleData> getUsageBuckets() { +        return mUsageBuckets; +    } + +    public static class Builder extends NetworkCycleData.Builder { +        private NetworkCycleChartData mObject = new NetworkCycleChartData(); + +        public Builder setUsageBuckets(List<NetworkCycleData> buckets) { +            getObject().mUsageBuckets = buckets; +            return this; +        } + +        @Override +        protected NetworkCycleChartData getObject() { +            return mObject; +        } + +        @Override +        public NetworkCycleChartData build() { +            return getObject(); +        } +    } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java new file mode 100644 index 000000000000..7ae3398d42ea --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import android.app.usage.NetworkStats; +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Loader for network data usage history. It returns a list of usage data per billing cycle with + * bucketized usages. + */ +public class NetworkCycleChartDataLoader +        extends NetworkCycleDataLoader<List<NetworkCycleChartData>> { + +    private static final String TAG = "NetworkCycleChartLoader"; + +    private final List<NetworkCycleChartData> mData; + +    private NetworkCycleChartDataLoader(Builder builder) { +        super(builder); +        mData = new ArrayList<NetworkCycleChartData>(); +    } + +    @Override +    void recordUsage(long start, long end) { +        try { +            final NetworkStats stats = mNetworkStatsManager.querySummary( +                mNetworkType, mSubId, start, end); +            final long total = getTotalUsage(stats); +            if (total > 0L) { +                final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder(); +                builder.setUsageBuckets(getUsageBuckets(start, end)) +                    .setStartTime(start) +                    .setEndTime(end) +                    .setTotalUsage(total); +                mData.add(builder.build()); +            } +        } catch (RemoteException e) { +            Log.e(TAG, "Exception querying network detail.", e); +        } +    } + +    @Override +    List<NetworkCycleChartData> getCycleUsage() { +        return mData; +    } + +    public static Builder<?> builder(Context context) { +        return new Builder<NetworkCycleChartDataLoader>(context) { +            @Override +            public NetworkCycleChartDataLoader build() { +                return new NetworkCycleChartDataLoader(this); +            } +        }; +    } + +    private List<NetworkCycleData> getUsageBuckets(long start, long end) { +        final List<NetworkCycleData> data = new ArrayList<>(); +        long bucketStart = start; +        long bucketEnd = start + NetworkCycleChartData.BUCKET_DURATION_MS; +        while (bucketEnd <= end) { +            long usage = 0L; +            try { +                final NetworkStats stats = mNetworkStatsManager.querySummary( +                    mNetworkType, mSubId, bucketStart, bucketEnd); +                usage = getTotalUsage(stats); +            } catch (RemoteException e) { +                Log.e(TAG, "Exception querying network detail.", e); +            } +            data.add(new NetworkCycleData.Builder() +                .setStartTime(bucketStart).setEndTime(bucketEnd).setTotalUsage(usage).build()); +            bucketStart = bucketEnd; +            bucketEnd += NetworkCycleChartData.BUCKET_DURATION_MS; +        } +        return data; +    } + +    public static abstract class Builder<T extends NetworkCycleChartDataLoader> +            extends NetworkCycleDataLoader.Builder<T> { + +        public Builder(Context context) { +            super(context); +        } + +    } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java new file mode 100644 index 000000000000..26c65a2c4a48 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +/** + * Base data structure representing usage data in a billing cycle. + */ +public class NetworkCycleData { + +    private long mStartTime; +    private long mEndTime; +    private long mTotalUsage; + +    protected NetworkCycleData() { +    } + +    public long getStartTime() { +        return mStartTime; +    } + +    public long getEndTime() { +        return mEndTime; +    } + +    public long getTotalUsage() { +        return mTotalUsage; +    } + +    public static class Builder { + +        private NetworkCycleData mObject = new NetworkCycleData(); + +        public Builder setStartTime(long start) { +            getObject().mStartTime = start; +            return this; +        } + +        public Builder setEndTime(long end) { +            getObject().mEndTime = end; +            return this; +        } + +        public Builder setTotalUsage(long total) { +            getObject().mTotalUsage = total; +            return this; +        } + +        protected NetworkCycleData getObject() { +            return mObject; +        } + +        public NetworkCycleData build() { +            return getObject(); +        } +    } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java new file mode 100644 index 000000000000..9d13717bbbcc --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import java.util.concurrent.TimeUnit; + +/** + * Usage data in a billing cycle for a specific Uid. + */ +public class NetworkCycleDataForUid extends NetworkCycleData { + +    private long mBackgroudUsage; +    private long mForegroudUsage; + +    private NetworkCycleDataForUid() { +    } + +    public long getBackgroudUsage() { +        return mBackgroudUsage; +    } + +    public long getForegroudUsage() { +        return mForegroudUsage; +    } + +    public static class Builder extends NetworkCycleData.Builder { + +        private NetworkCycleDataForUid mObject = new NetworkCycleDataForUid(); + +        public Builder setBackgroundUsage(long backgroundUsage) { +            getObject().mBackgroudUsage = backgroundUsage; +            return this; +        } + +        public Builder setForegroundUsage(long foregroundUsage) { +            getObject().mForegroudUsage = foregroundUsage; +            return this; +        } + +        @Override +        public NetworkCycleDataForUid getObject() { +            return mObject; +        } + +        @Override +        public NetworkCycleDataForUid build() { +            return getObject(); +        } +    } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java new file mode 100644 index 000000000000..95efb4cea491 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static android.app.usage.NetworkStats.Bucket.STATE_FOREGROUND; +import static android.net.NetworkStats.TAG_NONE; + +import android.app.usage.NetworkStats; +import android.content.Context; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Loader for network data usage history. It returns a list of usage data per billing cycle for a + * specific Uid. + */ +public class NetworkCycleDataForUidLoader extends +        NetworkCycleDataLoader<List<NetworkCycleDataForUid>> { +    private static final String TAG = "NetworkDataForUidLoader"; + +    private final List<NetworkCycleDataForUid> mData; +    private final int mUid; + +    private NetworkCycleDataForUidLoader(Builder builder) { +        super(builder); +        mUid = builder.mUid; +        mData = new ArrayList<NetworkCycleDataForUid>(); +    } + +    @Override +    void recordUsage(long start, long end) { +        try { +            final NetworkStats stats = mNetworkStatsManager.queryDetailsForUid( +                mNetworkType, mSubId, start, end, mUid); +            final long total = getTotalUsage(stats); +            if (total > 0L) { +                final long foreground = getForegroundUsage(start, end); +                final NetworkCycleDataForUid.Builder builder = new NetworkCycleDataForUid.Builder(); +                builder.setBackgroundUsage(total - foreground) +                    .setForegroundUsage(foreground) +                    .setStartTime(start) +                    .setEndTime(end) +                    .setTotalUsage(total); +                mData.add(builder.build()); +            } +        } catch (Exception e) { +            Log.e(TAG, "Exception querying network detail.", e); +        } +    } + +    @Override +    List<NetworkCycleDataForUid> getCycleUsage() { +        return mData; +    } + +    public static Builder<?> builder(Context context) { +        return new Builder<NetworkCycleDataForUidLoader>(context) { +            @Override +            public NetworkCycleDataForUidLoader build() { +                return new NetworkCycleDataForUidLoader(this); +            } +        }; +    } + +    private long getForegroundUsage(long start, long end) { +        final NetworkStats stats = mNetworkStatsManager.queryDetailsForUidTagState( +            mNetworkType, mSubId, start, end, mUid, TAG_NONE, STATE_FOREGROUND); +        return getTotalUsage(stats); +    } + +    public static abstract class Builder<T extends NetworkCycleDataForUidLoader> +            extends NetworkCycleDataLoader.Builder<T> { + +        private int mUid; + +        public Builder(Context context) { +            super(context); +        } + +        public Builder<T> setUid(int uid) { +            mUid = uid; +            return this; +        } +    } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java new file mode 100644 index 000000000000..cc936d2485c5 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static android.net.NetworkStatsHistory.FIELD_RX_BYTES; +import static android.net.NetworkStatsHistory.FIELD_TX_BYTES; + +import android.app.usage.NetworkStats; +import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; +import android.net.NetworkPolicy; +import android.net.NetworkPolicyManager; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.net.TrafficStats; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.format.DateUtils; +import android.util.Pair; + +import java.time.ZonedDateTime; +import java.util.Iterator; + +import androidx.annotation.VisibleForTesting; +import androidx.loader.content.AsyncTaskLoader; + +/** + * Loader for network data usage history. It returns a list of usage data per billing cycle. + */ +public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> { +    private static final String TAG = "NetworkCycleDataLoader"; +    protected final NetworkStatsManager mNetworkStatsManager; +    protected final String mSubId; +    protected final int mNetworkType; +    private final NetworkPolicy mPolicy; +    private final NetworkTemplate mNetworkTemplate; +    @VisibleForTesting +    final INetworkStatsService mNetworkStatsService; + +    protected NetworkCycleDataLoader(Builder<?> builder) { +        super(builder.mContext); +        mPolicy = builder.mPolicy; +        mSubId = builder.mSubId; +        mNetworkType = builder.mNetworkType; +        mNetworkTemplate = builder.mNetworkTemplate; +        mNetworkStatsManager = (NetworkStatsManager) +            builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE); +        mNetworkStatsService = INetworkStatsService.Stub.asInterface( +            ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); +    } + +    @Override +    protected void onStartLoading() { +        super.onStartLoading(); +        forceLoad(); +    } + +    public D loadInBackground() { +        if (mPolicy == null) { +            loadFourWeeksData(); +        } else { +            loadPolicyData(); +        } +        return getCycleUsage(); +    } + +    @VisibleForTesting +    void loadPolicyData() { +        final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator = +            NetworkPolicyManager.cycleIterator(mPolicy); +        while (iterator.hasNext()) { +            final Pair<ZonedDateTime, ZonedDateTime> cycle = iterator.next(); +            final long cycleStart = cycle.first.toInstant().toEpochMilli(); +            final long cycleEnd = cycle.second.toInstant().toEpochMilli(); +            recordUsage(cycleStart, cycleEnd); +        } +    } + +    @Override +    protected void onStopLoading() { +        super.onStopLoading(); +        cancelLoad(); +    } + +    @Override +    protected void onReset() { +        super.onReset(); +        cancelLoad(); +    } + +    @VisibleForTesting +    void loadFourWeeksData() { +        try { +            final INetworkStatsSession networkSession = mNetworkStatsService.openSession(); +            final NetworkStatsHistory networkHistory = networkSession.getHistoryForNetwork( +                mNetworkTemplate, FIELD_RX_BYTES | FIELD_TX_BYTES); +            final long historyStart = networkHistory.getStart(); +            final long historyEnd = networkHistory.getEnd(); + +            long cycleEnd = historyEnd; +            while (cycleEnd > historyStart) { +                final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4); +                recordUsage(cycleStart, cycleEnd); +                cycleEnd = cycleStart; +            } + +            TrafficStats.closeQuietly(networkSession); +        } catch (RemoteException e) { +            throw new RuntimeException(e); +        } +    } + +    @VisibleForTesting +    abstract void recordUsage(long start, long end); + +    abstract D getCycleUsage(); + +    public static Builder<?> builder(Context context) { +        return new Builder<NetworkCycleDataLoader>(context) { +            @Override +            public NetworkCycleDataLoader build() { +                return null; +            } +        }; +    } + +    protected long getTotalUsage(NetworkStats stats) { +        long bytes = 0L; +        if (stats != null) { +            final NetworkStats.Bucket bucket = new NetworkStats.Bucket(); +            while (stats.hasNextBucket() && stats.getNextBucket(bucket)) { +                bytes += bucket.getRxBytes() + bucket.getTxBytes(); +            } +            stats.close(); +        } +        return bytes; +    } + +    public static abstract class Builder<T extends NetworkCycleDataLoader> { +        private final Context mContext; +        private NetworkPolicy mPolicy; +        private String mSubId; +        private int mNetworkType; +        private NetworkTemplate mNetworkTemplate; + +        public Builder (Context context) { +            mContext = context; +        } + +        public Builder<T> setNetworkPolicy(NetworkPolicy policy) { +            mPolicy = policy; +            return this; +        } + +        public Builder<T> setSubscriberId(String subId) { +            mSubId = subId; +            return this; +        } + +        public Builder<T> setNetworkType(int networkType) { +            mNetworkType = networkType; +            return this; +        } + +        public Builder<T> setNetworkTemplate(NetworkTemplate template) { +            mNetworkTemplate = template; +            return this; +        } + +        public abstract T build(); +    } + +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java index a070b2a5f768..34e6097ea46e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsDetailLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java @@ -20,25 +20,23 @@ import android.app.usage.NetworkStatsManager;  import android.app.usage.NetworkStats;  import android.content.Context;  import android.os.RemoteException; -import android.telephony.TelephonyManager;  import android.util.Log;  import androidx.loader.content.AsyncTaskLoader;  /** - * Loader for retrieving the network stats details for all UIDs. + * Loader for retrieving the network stats summary for all UIDs.   */ -public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> { +public class NetworkStatsSummaryLoader extends AsyncTaskLoader<NetworkStats> {      private static final String TAG = "NetworkDetailLoader";      private final NetworkStatsManager mNetworkStatsManager; -    private final TelephonyManager mTelephonyManager;      private final long mStart;      private final long mEnd; -    private final int mSubId; +    private final String mSubId;      private final int mNetworkType; -    private NetworkStatsDetailLoader(Builder builder) { +    private NetworkStatsSummaryLoader(Builder builder) {          super(builder.mContext);          mStart = builder.mStart;          mEnd = builder.mEnd; @@ -46,8 +44,6 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {          mNetworkType = builder.mNetworkType;          mNetworkStatsManager = (NetworkStatsManager)                  builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE); -        mTelephonyManager = -                (TelephonyManager) builder.mContext.getSystemService(Context.TELEPHONY_SERVICE);      }      @Override @@ -59,8 +55,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {      @Override      public NetworkStats loadInBackground() {          try { -            return mNetworkStatsManager.queryDetails( -                    mNetworkType, mTelephonyManager.getSubscriberId(mSubId), mStart, mEnd); +            return mNetworkStatsManager.querySummary(mNetworkType, mSubId, mStart, mEnd);          } catch (RemoteException e) {              Log.e(TAG, "Exception querying network detail.", e);              return null; @@ -83,7 +78,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {          private final Context mContext;          private long mStart;          private long mEnd; -        private int mSubId; +        private String mSubId;          private int mNetworkType;          public Builder(Context context) { @@ -100,7 +95,7 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {              return this;          } -        public Builder setSubscriptionId(int subId) { +        public Builder setSubscriberId(String subId) {              mSubId = subId;              return this;          } @@ -110,8 +105,8 @@ public class NetworkStatsDetailLoader extends AsyncTaskLoader<NetworkStats> {              return this;          } -        public NetworkStatsDetailLoader build() { -            return new NetworkStatsDetailLoader(this); +        public NetworkStatsSummaryLoader build() { +            return new NetworkStatsSummaryLoader(this);          }      }  } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index fe0b35b4191c..089f773ec1e9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -163,6 +163,12 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {                  ? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi);      } +    /** Refresh the status label on Locale changed. */ +    public void refreshLocale() { +        updateStatusLabel(); +        mCallback.run(); +    } +      private String getValidSsid(WifiInfo info) {          String ssid = info.getSSID();          if (ssid != null && !WifiSsid.NONE.equals(ssid)) { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index 7baded8da1d4..62b5688fc9e6 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -118,7 +118,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify addDevice().       */      @Test -    public void testAddDevice_validCachedDevices_devicesAdded() { +    public void addDevice_validCachedDevices_devicesAdded() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -136,7 +136,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify getName().       */      @Test -    public void testGetName_validCachedDevice_nameFound() { +    public void getName_validCachedDevice_nameFound() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1); @@ -146,7 +146,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onDeviceNameUpdated().       */      @Test -    public void testOnDeviceNameUpdated_validName_nameUpdated() { +    public void onDeviceNameUpdated_validName_nameUpdated() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          assertThat(cachedDevice1.getName()).isEqualTo(DEVICE_ALIAS_1); @@ -161,7 +161,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify clearNonBondedDevices().       */      @Test -    public void testClearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() { +    public void clearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -193,7 +193,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify clearNonBondedDevices() for hearing aids.       */      @Test -    public void testClearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() { +    public void clearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() {          when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);          when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); @@ -214,7 +214,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId.       */      @Test -    public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() { +    public void onHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -247,7 +247,7 @@ public class CachedBluetoothDeviceManagerTest {       * device is connected and other is disconnected. The connected device should be chosen.       */      @Test -    public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() { +    public void onHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -282,7 +282,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId.       */      @Test -    public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() { +    public void onHiSyncIdChanged_differentHiSyncId_populateInSameList() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -316,7 +316,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onProfileConnectionStateChanged() for single hearing aid device connection.       */      @Test -    public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() { +    public void onProfileConnectionStateChanged_singleDeviceConnected_visible() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); @@ -353,7 +353,7 @@ public class CachedBluetoothDeviceManagerTest {       * devices are disconnected and they get connected.       */      @Test -    public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() { +    public void onProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -405,7 +405,7 @@ public class CachedBluetoothDeviceManagerTest {       * devices are connected and they get disconnected.       */      @Test -    public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() { +    public void onProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -458,7 +458,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair.       */      @Test -    public void testOnDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() { +    public void onDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -488,7 +488,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify OnDeviceUnpaired() for paired hearing Aid devices which are not a pair.       */      @Test -    public void testOnDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() { +    public void onDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -532,7 +532,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify addDevice() for hearing aid devices with same HiSyncId.       */      @Test -    public void testAddDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() { +    public void addDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() {          doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)              .getHearingAidProfile();          doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -560,7 +560,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify addDevice() for hearing aid devices with different HiSyncId.       */      @Test -    public void testAddDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() { +    public void addDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() {          doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)              .getHearingAidProfile();          doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -592,7 +592,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify getHearingAidPairDeviceSummary() for hearing aid devices with same HiSyncId.       */      @Test -    public void testGetHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() { +    public void getHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() {          mCachedDevice1.setHiSyncId(HISYNCID1);          mCachedDevice2.setHiSyncId(HISYNCID1);          mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); @@ -609,7 +609,7 @@ public class CachedBluetoothDeviceManagerTest {       * HiSyncId.       */      @Test -    public void testGetHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() { +    public void getHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() {          mCachedDevice1.setHiSyncId(HISYNCID1);          mCachedDevice2.setHiSyncId(HISYNCID2);          mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); @@ -625,7 +625,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify updateHearingAidsDevices().       */      @Test -    public void testUpdateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() { +    public void updateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() {          doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)              .getHearingAidProfile();          doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -643,7 +643,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onBtClassChanged().       */      @Test -    public void testOnBtClassChanged_validBtClass_classChanged() { +    public void onBtClassChanged_validBtClass_classChanged() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1); @@ -658,7 +658,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onDeviceDisappeared().       */      @Test -    public void testOnDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() { +    public void onDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull(); @@ -673,7 +673,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onActiveDeviceChanged().       */      @Test -    public void testOnActiveDeviceChanged_connectedDevices_activeDeviceChanged() { +    public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -736,7 +736,7 @@ public class CachedBluetoothDeviceManagerTest {       * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.       */      @Test -    public void testOnActiveDeviceChanged_withA2dpAndHearingAid() { +    public void onActiveDeviceChanged_withA2dpAndHearingAid() {          CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);          assertThat(cachedDevice1).isNotNull();          CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index c18db11a71a3..f6201dd0b5f1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;  import static org.mockito.Matchers.any;  import static org.mockito.Matchers.anyString;  import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn;  import static org.mockito.Mockito.never;  import static org.mockito.Mockito.spy;  import static org.mockito.Mockito.verify; @@ -79,74 +80,74 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testGetConnectionSummary_testSingleProfileConnectDisconnect() { +    public void getConnectionSummary_testSingleProfileConnectDisconnect() {          // Test without battery level          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Test with battery level          mBatteryLevel = 10;          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();      }      @Test -    public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() { +    public void getConnectionSummary_testMultipleProfileConnectDisconnect() {          mBatteryLevel = 10;          // Set HFP, A2DP and PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");          // Disconnect HFP only and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(                  "10% battery");          // Disconnect A2DP only and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(                  "10% battery");          // Disconnect both HFP and A2DP and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(                  "10% battery");          // Disconnect all profiles and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();      }      @Test -    public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() { +    public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() {          // Test without battery level          // Set A2DP profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set device as Active for A2DP and test connection state summary @@ -159,26 +160,26 @@ public class CachedBluetoothDeviceTest {                  "Active, 10% battery");          // Set A2DP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set A2DP profile to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");          // Set A2DP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();      }      @Test -    public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() { +    public void getConnectionSummary_testSingleProfileActiveDeviceHfp() {          // Test without battery level          // Set HFP profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set device as Active for HFP and test connection state summary @@ -193,26 +194,26 @@ public class CachedBluetoothDeviceTest {                  "Active, 10% battery");          // Set HFP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set HFP profile to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");          // Set HFP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();      }      @Test -    public void testGetConnectionSummary_testSingleProfileActiveDeviceHearingAid() { +    public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() {          // Test without battery level          // Set Hearing Aid profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set device as Active for Hearing Aid and test connection state summary @@ -227,11 +228,11 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testGetConnectionSummary_testMultipleProfilesActiveDevice() { +    public void getConnectionSummary_testMultipleProfilesActiveDevice() {          // Test without battery level          // Set A2DP and HFP profiles to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();          // Set device as Active for A2DP and HFP and test connection state summary @@ -246,14 +247,14 @@ public class CachedBluetoothDeviceTest {          // Disconnect A2DP only and test connection state summary          mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(                  "10% battery");          // Disconnect HFP only and test connection state summary          mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(                  "Active, 10% battery"); @@ -261,15 +262,15 @@ public class CachedBluetoothDeviceTest {          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set A2DP and HFP profiles to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);          assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");          // Set A2DP and HFP profiles to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getConnectionSummary()).isNull();      } @@ -277,32 +278,32 @@ public class CachedBluetoothDeviceTest {      public void getCarConnectionSummary_singleProfileConnectDisconnect() {          // Test without battery level          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();          // Test with battery level          mBatteryLevel = 10;          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set PAN profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      } @@ -311,29 +312,29 @@ public class CachedBluetoothDeviceTest {          mBatteryLevel = 10;          // Set HFP, A2DP and PAN profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");          // Disconnect HFP only and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(                  "Connected (no phone), battery 10%");          // Disconnect A2DP only and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(                  "Connected (no media), battery 10%");          // Disconnect both HFP and A2DP and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(                  "Connected (no phone or media), battery 10%");          // Disconnect all profiles and test connection state summary -        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      } @@ -341,7 +342,7 @@ public class CachedBluetoothDeviceTest {      public void getCarConnectionSummary_singleProfileActiveDeviceA2dp() {          // Test without battery level          // Set A2DP profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set device as Active for A2DP and test connection state summary @@ -354,18 +355,18 @@ public class CachedBluetoothDeviceTest {                  "Connected, battery 10%, active (media)");          // Set A2DP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set A2DP profile to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)");          // Set A2DP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      } @@ -373,7 +374,7 @@ public class CachedBluetoothDeviceTest {      public void getCarConnectionSummary_singleProfileActiveDeviceHfp() {          // Test without battery level          // Set HFP profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set device as Active for HFP and test connection state summary @@ -386,18 +387,18 @@ public class CachedBluetoothDeviceTest {                  "Connected, battery 10%, active (phone)");          // Set HFP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set HFP profile to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)");          // Set HFP profile to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      } @@ -405,7 +406,7 @@ public class CachedBluetoothDeviceTest {      public void getCarConnectionSummary_singleProfileActiveDeviceHearingAid() {          // Test without battery level          // Set Hearing Aid profile to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set device as Active for Hearing Aid and test connection state summary @@ -414,8 +415,7 @@ public class CachedBluetoothDeviceTest {          // Set Hearing Aid profile to be disconnected and test connection state summary          mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID); -        mCachedDevice.onProfileStateChanged(mHearingAidProfile, -                BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      } @@ -423,8 +423,8 @@ public class CachedBluetoothDeviceTest {      public void getCarConnectionSummary_multipleProfilesActiveDevice() {          // Test without battery level          // Set A2DP and HFP profiles to be connected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");          // Set device as Active for A2DP and HFP and test connection state summary @@ -439,14 +439,14 @@ public class CachedBluetoothDeviceTest {          // Disconnect A2DP only and test connection state summary          mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(                  "Connected (no media), battery 10%, active (phone)");          // Disconnect HFP only and test connection state summary          mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(                  "Connected (no phone), battery 10%, active (media)"); @@ -454,21 +454,21 @@ public class CachedBluetoothDeviceTest {          // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level          mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;          // Set A2DP and HFP profiles to be connected, Active and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);          mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);          assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active");          // Set A2DP and HFP profiles to be disconnected and test connection state summary -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.getCarConnectionSummary()).isNull();      }      @Test -    public void testDeviceName_testAliasNameAvailable() { +    public void deviceName_testAliasNameAvailable() {          when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);          when(mDevice.getName()).thenReturn(DEVICE_NAME);          CachedBluetoothDevice cachedBluetoothDevice = @@ -480,7 +480,7 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testDeviceName_testNameNotAvailable() { +    public void deviceName_testNameNotAvailable() {          CachedBluetoothDevice cachedBluetoothDevice =                  new CachedBluetoothDevice(mContext, mProfileManager, mDevice);          // Verify device address is returned on getName @@ -490,7 +490,7 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testDeviceName_testRenameDevice() { +    public void deviceName_testRenameDevice() {          final String[] alias = {DEVICE_ALIAS};          doAnswer(invocation -> alias[0]).when(mDevice).getAliasName();          doAnswer(invocation -> { @@ -513,7 +513,7 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testSetActive() { +    public void setActive() {          when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);          when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);          when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true); @@ -521,19 +521,19 @@ public class CachedBluetoothDeviceTest {          assertThat(mCachedDevice.setActive()).isFalse(); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.setActive()).isTrue(); -        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);          assertThat(mCachedDevice.setActive()).isTrue(); -        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);          assertThat(mCachedDevice.setActive()).isFalse();      }      @Test -    public void testIsA2dpDevice_isA2dpDevice() { +    public void isA2dpDevice_isA2dpDevice() {          when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);          when(mA2dpProfile.getConnectionStatus(mDevice)).                  thenReturn(BluetoothProfile.STATE_CONNECTED); @@ -542,7 +542,7 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testIsA2dpDevice_isNotA2dpDevice() { +    public void isA2dpDevice_isNotA2dpDevice() {          when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);          when(mA2dpProfile.getConnectionStatus(mDevice)).                  thenReturn(BluetoothProfile.STATE_DISCONNECTING); @@ -551,7 +551,7 @@ public class CachedBluetoothDeviceTest {      }      @Test -    public void testIsHfpDevice_isHfpDevice() { +    public void isHfpDevice_isHfpDevice() {          when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);          when(mHfpProfile.getConnectionStatus(mDevice)).                  thenReturn(BluetoothProfile.STATE_CONNECTED); @@ -637,4 +637,24 @@ public class CachedBluetoothDeviceTest {          verify(mDevice, never()).setAlias(any());      } + +    @Test +    public void getProfileConnectionState_nullProfile_returnDisconnected() { +        assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo( +                BluetoothProfile.STATE_DISCONNECTED); +    } + +    @Test +    public void getProfileConnectionState_profileConnected_returnConnected() { +        doReturn(BluetoothProfile.STATE_CONNECTED).when(mA2dpProfile).getConnectionStatus( +                any(BluetoothDevice.class)); + +        assertThat(mCachedDevice.getProfileConnectionState(mA2dpProfile)).isEqualTo( +                BluetoothProfile.STATE_CONNECTED); +    } + +    private void updateProfileStatus(LocalBluetoothProfile profile, int status) { +        doReturn(status).when(profile).getConnectionStatus(mDevice); +        mCachedDevice.onProfileStateChanged(profile, status); +    }  } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java new file mode 100644 index 000000000000..9bb53ee6a343 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSap; +import android.bluetooth.BluetoothProfile; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadow.api.Shadow; + +@RunWith(SettingsLibRobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class SapProfileTest { + +    @Mock +    private CachedBluetoothDeviceManager mDeviceManager; +    @Mock +    private LocalBluetoothProfileManager mProfileManager; +    @Mock +    private BluetoothSap mService; +    @Mock +    private CachedBluetoothDevice mCachedBluetoothDevice; +    @Mock +    private BluetoothDevice mBluetoothDevice; +    private BluetoothProfile.ServiceListener mServiceListener; +    private SapProfile mProfile; +    private ShadowBluetoothAdapter mShadowBluetoothAdapter; + +    @Before +    public void setUp() { +        MockitoAnnotations.initMocks(this); +        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        mProfile = new SapProfile(RuntimeEnvironment.application, mDeviceManager, mProfileManager); +        mServiceListener = mShadowBluetoothAdapter.getServiceListener(); +        mServiceListener.onServiceConnected(BluetoothProfile.SAP, mService); +    } + +    @Test +    public void connect_shouldConnectBluetoothSap() { +        mProfile.connect(mBluetoothDevice); +        verify(mService).connect(mBluetoothDevice); +    } + +    @Test +    public void disconnect_shouldDisconnectBluetoothSap() { +        mProfile.disconnect(mBluetoothDevice); +        verify(mService).disconnect(mBluetoothDevice); +    } + +    @Test +    public void getConnectionStatus_shouldReturnConnectionState() { +        when(mService.getConnectionState(mBluetoothDevice)). +                thenReturn(BluetoothProfile.STATE_CONNECTED); +        assertThat(mProfile.getConnectionStatus(mBluetoothDevice)). +                isEqualTo(BluetoothProfile.STATE_CONNECTED); +    } +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java index c23ad79a52fe..887c1d57c870 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java @@ -38,13 +38,13 @@ import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;  import com.android.settingslib.core.lifecycle.events.OnResume;  import com.android.settingslib.core.lifecycle.events.OnStart;  import com.android.settingslib.core.lifecycle.events.OnStop; -import com.android.settingslib.testutils.FragmentTestUtils;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.robolectric.Robolectric;  import org.robolectric.android.controller.ActivityController; +import org.robolectric.shadows.androidx.fragment.FragmentController;  @RunWith(SettingsLibRobolectricTestRunner.class)  public class LifecycleTest { @@ -184,7 +184,7 @@ public class LifecycleTest {      @Test      public void runThroughDialogFragmentLifecycles_shouldObserveEverything() {          final TestDialogFragment fragment = new TestDialogFragment(); -        FragmentTestUtils.startFragment(fragment); +        FragmentController.setupFragment(fragment);          fragment.onCreateOptionsMenu(null, null);          fragment.onPrepareOptionsMenu(null); @@ -208,7 +208,7 @@ public class LifecycleTest {      @Test      public void runThroughFragmentLifecycles_shouldObserveEverything() {          final TestFragment fragment = new TestFragment(); -        FragmentTestUtils.startFragment(fragment); +        FragmentController.setupFragment(fragment);          fragment.onCreateOptionsMenu(null, null);          fragment.onPrepareOptionsMenu(null); @@ -248,7 +248,7 @@ public class LifecycleTest {      @Test      public void onOptionItemSelectedShortCircuitsIfAnObserverHandlesTheMenuItem() {          final TestFragment fragment = new TestFragment(); -        FragmentTestUtils.startFragment(fragment); +        FragmentController.setupFragment(fragment);          final OptionItemAccepter accepter = new OptionItemAccepter();          fragment.getLifecycle().addObserver(accepter); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java index 96b2a1433f53..b00476b24921 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java @@ -50,7 +50,7 @@ public class LicenseHtmlGeneratorFromXmlTest {              + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n"              + "</licenses2>"; -    private static final String EXPECTED_HTML_STRING = +    private static final String HTML_HEAD_STRING =              "<html><head>\n"              + "<style type=\"text/css\">\n"              + "body { padding: 0; font-family: sans-serif; }\n" @@ -63,8 +63,12 @@ public class LicenseHtmlGeneratorFromXmlTest {              + "</head>"              + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"              + "<div class=\"toc\">\n" -            + "<ul>\n" -            + "<li><a href=\"#id0\">/file0</a></li>\n" +            + "<ul>\n"; + +    private static final String HTML_CUSTOM_HEADING = "Custom heading"; + +    private static final String HTML_BODY_STRING = +            "<li><a href=\"#id0\">/file0</a></li>\n"              + "<li><a href=\"#id0\">/file1</a></li>\n"              + "</ul>\n"              + "</div><!-- table of contents -->\n" @@ -81,6 +85,11 @@ public class LicenseHtmlGeneratorFromXmlTest {              + "</td></tr><!-- same-license -->\n"              + "</table></body></html>\n"; +    private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING; + +    private static final String EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING = +            HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING; +      @Test      public void testParseValidXmlStream() throws XmlPullParserException, IOException {          Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); @@ -117,7 +126,23 @@ public class LicenseHtmlGeneratorFromXmlTest {          StringWriter output = new StringWriter();          LicenseHtmlGeneratorFromXml.generateHtml( -                fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output)); +                fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), "");          assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING);      } + +    @Test +    public void testGenerateHtmlWithCustomHeading() { +        Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); +        Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + +        fileNameToContentIdMap.put("/file0", "0"); +        fileNameToContentIdMap.put("/file1", "0"); +        contentIdToFileContentMap.put("0", "license content #0"); + +        StringWriter output = new StringWriter(); +        LicenseHtmlGeneratorFromXml.generateHtml( +                fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), +                HTML_CUSTOM_HEADING); +        assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING); +    }  } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java index 12a4e699fb76..c32cc99daf96 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java @@ -142,7 +142,7 @@ public class LicenseHtmlLoaderCompatTest {          }          @Implementation -        static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) { +        static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) {              return sGenerateHtmlFileSucceeded;          }      } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java new file mode 100644 index 000000000000..3dc110d30e1e --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.net.ConnectivityManager; +import android.os.RemoteException; +import android.text.format.DateUtils; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class NetworkCycleChartDataLoaderTest { + +    @Mock +    private NetworkStatsManager mNetworkStatsManager; +    @Mock +    private Context mContext; + +    private NetworkCycleChartDataLoader mLoader; + +    @Before +    public void setUp() { +        MockitoAnnotations.initMocks(this); +        when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE)) +            .thenReturn(mNetworkStatsManager); +    } + +    @Test +    public void recordUsage_shouldQueryNetworkSummary() throws RemoteException { +        final long end = System.currentTimeMillis(); +        final long start = end - (DateUtils.WEEK_IN_MILLIS * 4); +        final int networkType = ConnectivityManager.TYPE_MOBILE; +        final String subId = "TestSubscriber"; +        mLoader = NetworkCycleChartDataLoader.builder(mContext) +            .setNetworkType(networkType).setSubscriberId(subId).build(); + +        mLoader.recordUsage(start, end); + +        verify(mNetworkStatsManager).querySummary(networkType, subId, start, end); +    } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java new file mode 100644 index 000000000000..53fe45197236 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.net.ConnectivityManager; +import android.text.format.DateUtils; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class NetworkCycleDataForUidLoaderTest { + +    @Mock +    private NetworkStatsManager mNetworkStatsManager; +    @Mock +    private Context mContext; + +    private NetworkCycleDataForUidLoader mLoader; + +    @Before +    public void setUp() { +        MockitoAnnotations.initMocks(this); +        when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE)) +            .thenReturn(mNetworkStatsManager); +    } + +    @Test +    public void recordUsage_shouldQueryNetworkDetailsForUid() { +        final long end = System.currentTimeMillis(); +        final long start = end - (DateUtils.WEEK_IN_MILLIS * 4); +        final int networkType = ConnectivityManager.TYPE_MOBILE; +        final String subId = "TestSubscriber"; +        final int uid = 1; +        mLoader = NetworkCycleDataForUidLoader.builder(mContext) +            .setUid(uid).setNetworkType(networkType).setSubscriberId(subId).build(); + +        mLoader.recordUsage(start, end); + +        verify(mNetworkStatsManager).queryDetailsForUid(networkType, subId, start, end, uid); +    } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java new file mode 100644 index 000000000000..be7f1bbb280f --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.nullable; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; +import android.net.NetworkPolicy; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.os.RemoteException; +import android.text.format.DateUtils; +import android.util.Range; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.util.ReflectionHelpers; + +import java.time.ZonedDateTime; +import java.util.Iterator; +import java.util.List; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class NetworkCycleDataLoaderTest { + +    @Mock +    private NetworkStatsManager mNetworkStatsManager; +    @Mock +    private Context mContext; +    @Mock +    private NetworkPolicy mPolicy; +    @Mock +    private Iterator<Range<ZonedDateTime>> mIterator; +    @Mock +    private INetworkStatsService mNetworkStatsService; +    @Mock +    private NetworkCycleDataLoader.Builder mBuilder; + + +    private NetworkCycleDataTestLoader mLoader; + +    @Before +    public void setUp() { +        MockitoAnnotations.initMocks(this); +        when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE)) +            .thenReturn(mNetworkStatsManager); +        when(mPolicy.cycleIterator()).thenReturn(mIterator); +    } + +    @Test +    public void loadInBackground_noNetworkPolicy_shouldLoad4WeeksData() { +        mLoader = spy(new NetworkCycleDataTestLoader(mContext)); +        doNothing().when(mLoader).loadFourWeeksData(); + +        mLoader.loadInBackground(); + +        verify(mLoader).loadFourWeeksData(); +    } + +    @Test +    public void loadInBackground_hasNetworkPolicy_shouldLoadPolicyData() { +        mLoader = spy(new NetworkCycleDataTestLoader(mContext)); +        ReflectionHelpers.setField(mLoader, "mPolicy", mPolicy); + +        mLoader.loadInBackground(); + +        verify(mLoader).loadPolicyData(); +    } + +    @Test +    public void loadPolicyData_shouldRecordUsageFromPolicyCycle() { +        final int networkType = ConnectivityManager.TYPE_MOBILE; +        final String subId = "TestSubscriber"; +        final ZonedDateTime now = ZonedDateTime.now(); +        final Range<ZonedDateTime> cycle = new Range<>(now, now); +        final long nowInMs = now.toInstant().toEpochMilli(); +        // mock 1 cycle data. +        // hasNext() will be called internally in next(), hence setting it to return true twice. +        when(mIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); +        when(mIterator.next()).thenReturn(cycle); +        mLoader = spy(new NetworkCycleDataTestLoader(mContext)); +        ReflectionHelpers.setField(mLoader, "mPolicy", mPolicy); +        ReflectionHelpers.setField(mLoader, "mNetworkType", networkType); +        ReflectionHelpers.setField(mLoader, "mSubId", subId); + +        mLoader.loadPolicyData(); + +        verify(mLoader).recordUsage(nowInMs, nowInMs); +    } + +    @Test +    public void loadFourWeeksData_shouldRecordUsageForLast4Weeks() throws RemoteException { +        mLoader = spy(new NetworkCycleDataTestLoader(mContext)); +        ReflectionHelpers.setField(mLoader, "mNetworkStatsService", mNetworkStatsService); +        final INetworkStatsSession networkSession = mock(INetworkStatsSession.class); +        when(mNetworkStatsService.openSession()).thenReturn(networkSession); +        final NetworkStatsHistory networkHistory = mock(NetworkStatsHistory.class); +        when(networkSession.getHistoryForNetwork(nullable(NetworkTemplate.class), anyInt())) +            .thenReturn(networkHistory); +        final long now = System.currentTimeMillis(); +        final long fourWeeksAgo = now - (DateUtils.WEEK_IN_MILLIS * 4); +        when(networkHistory.getStart()).thenReturn(fourWeeksAgo); +        when(networkHistory.getEnd()).thenReturn(now); + +        mLoader.loadFourWeeksData(); + +        verify(mLoader).recordUsage(fourWeeksAgo, now); +    } + +    public class NetworkCycleDataTestLoader extends NetworkCycleDataLoader<List<NetworkCycleData>> { + +        private NetworkCycleDataTestLoader(Context context) { +            super(NetworkCycleDataLoader.builder(mContext)); +            mContext = context; +        } + +        @Override +        void recordUsage(long start, long end) { +        } + +        @Override +        List<NetworkCycleData> getCycleUsage() { +            return null; +        } +    } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java deleted file mode 100644 index d8e73b7db322..000000000000 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.testutils; - -import android.os.Bundle; -import android.widget.LinearLayout; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - -import org.robolectric.Robolectric; - -/** - * Utilities for creating Fragments for testing. - * <p> - * TODO(b/111195449) - Duplicated from org.robolectric.shadows.support.v4.SupportFragmentTestUtil - */ -@Deprecated -public class FragmentTestUtils { - -    public static void startFragment(Fragment fragment) { -        buildFragmentManager(FragmentUtilActivity.class) -                .beginTransaction().add(fragment, null).commit(); -    } - -    public static void startFragment(Fragment fragment, -            Class<? extends FragmentActivity> activityClass) { -        buildFragmentManager(activityClass) -                .beginTransaction().add(fragment, null).commit(); -    } - -    public static void startVisibleFragment(Fragment fragment) { -        buildFragmentManager(FragmentUtilActivity.class) -                .beginTransaction().add(1, fragment, null).commit(); -    } - -    public static void startVisibleFragment(Fragment fragment, -            Class<? extends FragmentActivity> activityClass, int containerViewId) { -        buildFragmentManager(activityClass) -                .beginTransaction().add(containerViewId, fragment, null).commit(); -    } - -    private static FragmentManager buildFragmentManager( -            Class<? extends FragmentActivity> activityClass) { -        FragmentActivity activity = Robolectric.setupActivity(activityClass); -        return activity.getSupportFragmentManager(); -    } - -    private static class FragmentUtilActivity extends FragmentActivity { -        @Override -        protected void onCreate(Bundle savedInstanceState) { -            super.onCreate(savedInstanceState); -            LinearLayout view = new LinearLayout(this); -            view.setId(1); - -            setContentView(view); -        } -    } -} diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index c53417b4e0f5..de86789053e9 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -55,7 +55,7 @@      <bool name="def_networks_available_notification_on">true</bool>      <bool name="def_backup_enabled">false</bool> -    <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string> +    <string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string>      <!-- Default value for whether or not to pulse the notification LED when there is a           pending notification --> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index bd21b8353136..c09b76394340 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -659,6 +659,9 @@ class SettingsProtoDumpUtil {          dumpSetting(s, p,                  Settings.Global.GPU_DEBUG_LAYERS,                  GlobalSettingsProto.Gpu.DEBUG_LAYERS); +        dumpSetting(s, p, +                Settings.Global.ANGLE_ENABLED_APP, +                GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);          p.end(gpuToken);          final long hdmiToken = p.start(GlobalSettingsProto.HDMI); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 63978ba60171..18ec9c34e98c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -870,7 +870,11 @@ public class SettingsProvider extends ContentProvider {                  }              }              if (newRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) -                    != prevRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)) { +                    != prevRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) || +                    newRestrictions.getBoolean( +                            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY) +                    != prevRestrictions.getBoolean( +                            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) {                  final long identity = Binder.clearCallingIdentity();                  try {                      synchronized (mLock) { @@ -3285,8 +3289,8 @@ public class SettingsProvider extends ContentProvider {                  if (currentVersion == 133) {                      // Version 133: Add default end button behavior                      final SettingsState systemSettings = getSystemSettingsLocked(userId); -                    if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR) == -                            null) { +                    if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR) +                            .isNull()) {                          String defaultEndButtonBehavior = Integer.toString(getContext()                                  .getResources().getInteger(R.integer.def_end_button_behavior));                          systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index da870bd134bf..5c654b44d1dc 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -151,6 +151,7 @@      <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />      <uses-permission android:name="android.permission.SUSPEND_APPS" /> +    <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />      <application android:label="@string/app_label"                   android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java index aa2fb32f13a8..814324e63d19 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java @@ -20,6 +20,7 @@ import android.view.View;  import com.android.systemui.plugins.Plugin;  import com.android.systemui.plugins.annotations.ProvidesInterface; +import java.io.PrintWriter;  @ProvidesInterface(action = NavGesture.ACTION, version = NavGesture.VERSION)  public interface NavGesture extends Plugin { @@ -46,6 +47,8 @@ public interface NavGesture extends Plugin {          public void onNavigationButtonLongPress(View v);          public default void destroy() { } + +        public default void dump(PrintWriter pw) { }      }  } diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml index 03ed62b3e600..75f43f9a5808 100644 --- a/packages/SystemUI/res/layout/qs_detail_buttons.xml +++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml @@ -26,6 +26,7 @@          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginEnd="8dp" +        android:minHeight="48dp"          android:minWidth="132dp"          android:textAppearance="@style/TextAppearance.QS.DetailButton"          android:focusable="true" /> @@ -35,6 +36,7 @@          style="@style/QSBorderlessButton"          android:layout_width="wrap_content"          android:layout_height="wrap_content" +        android:minHeight="48dp"          android:minWidth="88dp"          android:textAppearance="@style/TextAppearance.QS.DetailButton"          android:focusable="true"/> diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml index 11a01871b782..708326971454 100644 --- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml +++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml @@ -20,10 +20,13 @@      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:layout_weight="1" -    android:clipChildren="false" -    android:clipToPadding="false" +    android:clipChildren="true" +    android:clipToPadding="true" +    android:paddingStart="@dimen/notification_side_paddings" +    android:paddingEnd="@dimen/notification_side_paddings"      android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom"> +      <FrameLayout          android:id="@+id/page_decor"          android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 1bc2bcc84cce..157934f879bc 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Kies nuwe taakuitleg"</string>      <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Hulpboodskapgebied"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bevestig"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Raak die vingerafdruksensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Vingerafdrukikoon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Soek tans vir jou …"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gesig-ikoon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Berging"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Wenke"</string>      <string name="instant_apps" msgid="6647570248119804907">"Kitsprogramme"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Kitsprogramme hoef nie geïnstalleer te word nie."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> loop tans"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Program is oopgemaak sonder dat dit geïnstalleer is."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Program is oopgemaak sonder dat dit geïnstalleer is. Tik om meer te wete te kom."</string>      <string name="app_info" msgid="6856026610594615344">"Programinligting"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Gaan na blaaier"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Gaan na web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is af"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index b663fbd0e5bd..492fa8c0606e 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"የአዲስ ተግባር አቀማመጥን ይምረጡ"</string>      <string name="cancel" msgid="6442560571259935130">"ይቅር"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"የእገዛ መልዕክት አካባቢ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"አረጋግጥ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"የጣት አሻራ ዳሳሹን ይንኩ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"የጣት አሻራ አዶ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"እርስዎን በመፈለግ ላይ…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"የፊት አዶ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ማከማቻ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ፍንጮች"</string>      <string name="instant_apps" msgid="6647570248119804907">"የቅጽበት መተግበሪያዎች"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ቅጽበታዊ መተግበሪያዎች መጫን አያስፈልጋቸውም።"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"መተግበሪያ ሳይጫን ተከፍቷል።"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"መተግበሪያ ሳይጫን ተከፍቷል። ተጨማሪ ለማወቅ መታ ያድርጉ።"</string>      <string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ወደ አሳሽ ሂድ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ወደ ድር ሂድ"</string>      <string name="mobile_data" msgid="7094582042819250762">"የተንቀሳቃሽ ስልክ ውሂብ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>— <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ጠፍቷል"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 5f63aaf23b96..fe27bb705cb1 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -107,16 +107,12 @@      <string name="camera_label" msgid="7261107956054836961">"فتح الكاميرا"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"تحديد تنسيق جديد للمهمة"</string>      <string name="cancel" msgid="6442560571259935130">"إلغاء"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"منطقة رسالة المساعدة"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تأكيد"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"المس جهاز استشعار بصمات الإصبع"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"رمز بصمة الإصبع"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"جارٍ البحث عن وجهك…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"رمز الوجه"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"تم توصيل البلوتوث."</string> @@ -853,9 +849,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"تلميحات"</string>      <string name="instant_apps" msgid="6647570248119804907">"التطبيقات الفورية"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"لا تتطلب التطبيقات الفورية إجراء التثبيت."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"التطبيق <xliff:g id="APP">%1$s</xliff:g> قيد التشغيل"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"تمّ فتح التطبيق بدون تثبيته."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"تمّ فتح التطبيق بدون تثبيته. انقر لمعرفة مزيد من المعلومات."</string>      <string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string> -    <string name="go_to_web" msgid="2650669128861626071">"الانتقال إلى المتصفح"</string> +    <string name="go_to_web" msgid="1106022723459948514">"الانتقال إلى الويب"</string>      <string name="mobile_data" msgid="7094582042819250762">"بيانات الجوّال"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"تم إيقاف شبكة Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index d217663cfc52..8cde52453b8d 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"কেমেৰা খোলক"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কাৰ্যৰ চানেকি বাছনি কৰক"</string>      <string name="cancel" msgid="6442560571259935130">"বাতিল কৰক"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"সহায় বাৰ্তাৰ ক্ষেত্ৰ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"নিশ্চিত কৰক"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ফিংগাৰপ্ৰিণ্ট আইকন"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"আপোনাৰ মুখমণ্ডল বিচাৰি আছে…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"মুখমণ্ডলৰ আইকন"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"উপযোগিতা অনুসৰি জুম কৰা বুটাম।"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"স্ক্ৰীণৰ আকাৰ ডাঙৰ কৰিবলৈ জুম কৰক।"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ব্লুটুথ সংযোগ হ\'ল।"</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়াগাৰ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ইংগিতবোৰ"</string>      <string name="instant_apps" msgid="6647570248119804907">"তাৎক্ষণিক এপসমূহ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"তাৎক্ষণিক এপসমূহক ইনষ্টল কৰাৰ প্ৰয়োজন নাই।"</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"এপ্ সম্পৰ্কীয় তথ্য"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ব্ৰাউজাৰলৈ যাওক"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ৱেবলৈ যাওক"</string>      <string name="mobile_data" msgid="7094582042819250762">"ম\'বাইল ডেটা"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"ৱাই-ফাই অফ অৱস্থাত আছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index b4f6b4a8bdb1..2342a89abf8e 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"kemaranı açın"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni tapşırıq sxemi seçin"</string>      <string name="cancel" msgid="6442560571259935130">"Ləğv et"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yardım mesajı bölməsi"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Təsdiq"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Barmaq izi sensoruna klikləyin"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmaq izi ikonası"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Siz axtarılırsınız…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Üz işarəsi"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyğunluq zoom düyməsi."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha böyük ekranda uzaqlaşdır."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth qoşulub."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Yaddaş"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Məsləhətlər"</string>      <string name="instant_apps" msgid="6647570248119804907">"Ani Tətbiqlər"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Ani tətbiqlər quraşdırma tələb etmir."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> işləyir"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Quraşdırılmadan açılan tətbiq."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Quraşdırılmadan açılan tətbiq. Ətraflı məlumat üçün klikləyin."</string>      <string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Brauzerə daxil edin"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Vebə keçin"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobil data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi deaktivdir"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index fde90bcf6670..47422b2fa2fd 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberi novi raspored zadataka"</string>      <string name="cancel" msgid="6442560571259935130">"Otkaži"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblast poruke za pomoć"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdi"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor za otisak prsta"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otiska prsta"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme Zum kompatibilnosti."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje sa manjeg na veći ekran."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je priključen."</string> @@ -835,9 +831,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Memorijski prostor"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Saveti"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije ne zahtevaju instalaciju."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija se otvorila bez instaliranja."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija se otvorila bez instaliranja. Dodirnite da biste saznali više."</string>      <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Idi na pregledač"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Idi na veb"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index c8fbb92ceae0..de01516dca7b 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"адкрыць камеру"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Выберыце новы макет заданняў"</string>      <string name="cancel" msgid="6442560571259935130">"Скасаваць"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Поле даведачнага паведамлення"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Пацвердзіць"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Дакраніцеся да сканера адбіткаў пальцаў"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок адбіткаў пальцаў"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ідзе пошук вашага твару…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок твару"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка сумяшчальнасці маштаба."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Маштабаванне малых элементаў для большага экрана."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-сувязь."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Захоўванне"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Падказкі"</string>      <string name="instant_apps" msgid="6647570248119804907">"Імгненныя праграмы"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Імгненныя праграмы не патрабуюць усталёўкі."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" запушчана"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Праграма адкрыта без усталёўкі."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Праграма адкрыта без усталёўкі. Націсніце, каб даведацца больш."</string>      <string name="app_info" msgid="6856026610594615344">"Інфармацыя пра праграму"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Перайсці ў браўзер"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Перайсці ў інтэрнэт"</string>      <string name="mobile_data" msgid="7094582042819250762">"Маб. перадача даных"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi выключаны"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 75a63e6ffb12..29d89ecba9a0 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"отваряне на камерата"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Избиране на ново оформление за задачите"</string>      <string name="cancel" msgid="6442560571259935130">"Отказ"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област за помощно съобщение"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потвърждаване"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Докоснете сензора за отпечатъци"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона за отпечатък"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Търсим ви…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона на лице"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е включен."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Съвети"</string>      <string name="instant_apps" msgid="6647570248119804907">"Мигновени приложения"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"За мигновените приложения не се изисква инсталиране."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> работи"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Приложението се отвори, без да бъде инсталирано."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Приложението се отвори, без да бъде инсталирано. Докоснете, за да научите повече."</string>      <string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Към браузъра"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Към мрежата"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобилни данни"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Функцията за Wi‑Fi е изключена"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 38cfc8a519d8..d2f6401b4394 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -31,7 +31,7 @@      </plurals>      <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"কোনো বিজ্ঞপ্তি নেই"</string>      <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"চলতে-থাকা"</string> -    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string> +    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তি"</string>      <string name="battery_low_title" msgid="9187898087363540349">"চার্জ শীঘ্রই শেষ হয়ে যেতে পারে"</string>      <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>      <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> বাকি আছে, বর্তমান ব্যবহারের ভিত্তিতে আর <xliff:g id="TIME">%2$s</xliff:g> চলবে"</string> @@ -49,7 +49,7 @@      <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"অটো-রোটেট স্ক্রিন"</string>      <string name="status_bar_settings_mute_label" msgid="554682549917429396">"মিউট করুন"</string>      <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"স্বতঃ"</string> -    <string name="status_bar_settings_notifications" msgid="397146176280905137">"বিজ্ঞপ্তিগুলি"</string> +    <string name="status_bar_settings_notifications" msgid="397146176280905137">"বিজ্ঞপ্তি"</string>      <string name="bluetooth_tethered" msgid="7094101612161133267">"ব্লুটুথ টিথার করা হয়েছে"</string>      <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ইনপুট পদ্ধতিগুলি সেট আপ করুন"</string>      <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ফিজিক্যাল কীবোর্ড"</string> @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কার্য লেআউট বেছে নিন"</string>      <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"সহায়তার মেসেজ দেখানোর জায়গা"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"কনফার্ম করুন"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"আঙ্গুলের ছাপের আইকন"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"আপনার জন্য খোঁজা হচ্ছে…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ফেস আইকন"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string> @@ -180,7 +176,7 @@      <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ ব্যাটারি রয়েছে৷"</string>      <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ব্যাটারি চার্জ হচ্ছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ৷"</string>      <string name="accessibility_settings_button" msgid="799583911231893380">"সিস্টেম সেটিংস৷"</string> -    <string name="accessibility_notifications_button" msgid="4498000369779421892">"বিজ্ঞপ্তিগুলি৷"</string> +    <string name="accessibility_notifications_button" msgid="4498000369779421892">"বিজ্ঞপ্তি৷"</string>      <string name="accessibility_overflow_action" msgid="5681882033274783311">"সমস্ত বিজ্ঞপ্তি দেখুন"</string>      <string name="accessibility_remove_notification" msgid="3603099514902182350">"বিজ্ঞপ্তি সাফ করুন৷"</string>      <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS সক্ষম করা হয়েছে৷"</string> @@ -340,7 +336,7 @@        <item quantity="one">%dটি ডিভাইস</item>        <item quantity="other">%dটি ডিভাইস</item>      </plurals> -    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"বিজ্ঞপ্তিগুলি"</string> +    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"বিজ্ঞপ্তি"</string>      <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ফ্ল্যাশলাইট"</string>      <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"মোবাইল ডেটা"</string>      <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"ডেটার ব্যবহার"</string> @@ -685,7 +681,7 @@      <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>      <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>      <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string> -    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তিগুলি"</string> +    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তি"</string>      <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"কীবোর্ড শর্টকাট"</string>      <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"কীবোর্ড লে-আউট পাল্টান"</string>      <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"অ্যাপ্লিকেশানগুলি"</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"স্টোরেজ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"হিন্ট"</string>      <string name="instant_apps" msgid="6647570248119804907">"ঝটপট অ্যাপ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ঝটপট অ্যাপ ইনস্টল করার প্রয়োজন হয় না।"</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"অ্যাপের তথ্য"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ব্রাউজারে যান"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ওয়েবে যান"</string>      <string name="mobile_data" msgid="7094582042819250762">"মোবাইল ডেটা"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"ওয়াই ফাই বন্ধ আছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 9865cb8c85e5..ac0c05ecb0f7 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi raspored zadataka"</string>      <string name="cancel" msgid="6442560571259935130">"Otkaži"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Prostor za poruku za pomoć"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdite"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor za otisak prsta"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona za otisak prsta"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je povezan."</string> @@ -837,9 +833,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Savjeti"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant-aplikacije"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je otvorena bez prethodne instalacije."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je otvorena bez prethodne instalacije. Dodirnite da saznate više."</string>      <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Idi na preglednik"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Idite na internet"</string>      <string name="mobile_data" msgid="7094582042819250762">"Prijenos podataka"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"WiFi veza je isključena"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 1613613c0e53..b4a2f3bfc1d2 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selecciona el disseny de la tasca nova"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Àrea de missatge d\'ajuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirma"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor d\'empremtes digitals"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona d\'empremta digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"S\'està cercant la teva cara…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona facial"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Emmagatzematge"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Suggeriments"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplicacions instantànies"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"No cal instal·lar les aplicacions instantànies."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"S\'està executant <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"L\'aplicació s\'ha obert sense instal·lar-se."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"L\'aplicació s\'ha obert sense instal·lar-se. Toca per obtenir més informació."</string>      <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ves al navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Ves al web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dades mòbils"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"La Wi-Fi està desactivada"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 867225c089d9..6d4af4acac45 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Vybrat nové rozvržení úkolů"</string>      <string name="cancel" msgid="6442560571259935130">"Zrušit"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblast pro zprávu nápovědy"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdit"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotkněte se snímače otisků prstů"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otisku prstu"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hledáme vás…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona obličeje"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Úložiště"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Tipy"</string>      <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikace"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikace není třeba instalovat."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je spuštěna"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikace byla otevřena bez instalace."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikace byla otevřena bez instalace. Klepnutím zobrazíte další informace."</string>      <string name="app_info" msgid="6856026610594615344">"O aplikaci"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Přejít do prohlížeče"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Přejít na web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilní data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je vypnuta"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index baba3ac82483..ade7db114aa8 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Vælg nyt opgavelayout"</string>      <string name="cancel" msgid="6442560571259935130">"Annuller"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område med hjælpemeddelelse"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekræft"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sæt fingeren på fingeraftrykslæseren"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeraftryk"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Forsøger at finde dig…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansigt"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Lagerplads"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Tips"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps kræver ingen installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> kører"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"En app blev åbnet uden at blive installeret."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"En app blev åbnet uden at blive installeret. Tryk for at få flere oplysninger."</string>      <string name="app_info" msgid="6856026610594615344">"Appinfo"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Gå til en browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Gå til website"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er slået fra"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index e8c8c5c8ed76..06aac5c5d1a6 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"Kamera öffnen"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Neues Aufgabenlayout auswählen"</string>      <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Bereich für die Hilfemeldung"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bestätigen"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Berühre den Fingerabdrucksensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerabdruck-Symbol"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Wir suchen nach dir…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gesichtssymbol"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Mit Bluetooth verbunden"</string> @@ -833,9 +829,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Speicher"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hinweise"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant-Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Bei Instant-Apps ist keine vorherige Installation erforderlich."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> wird ausgeführt"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App wurde geöffnet, ohne vorher installiert zu werden."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App wurde geöffnet, ohne vorher installiert zu werden. Tippe, um weitere Informationen zu erhalten."</string>      <string name="app_info" msgid="6856026610594615344">"App-Informationen"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Browser öffnen"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Web aufrufen"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile Daten"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"WLAN ist deaktiviert"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 4765c9b2fd29..1892da634d3b 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"άνοιγμα φωτογραφικής μηχανής"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Επιλέξτε τη νέα διάταξη εργασίας"</string>      <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Περιοχή μηνυμάτων βοήθειας"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Επιβεβαίωση"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Αναζήτηση για εσάς…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Εικονίδιο προσώπου"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Το Bluetooth είναι συνδεδεμένο."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Αποθηκευτικός χώρος"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Συμβουλές"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Εφαρμογές"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Οι Instant Εφαρμογές δεν απαιτούν εγκατάσταση."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Η εφαρμογή άνοιξε χωρίς να έχει εγκατασταθεί."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Η εφαρμογή άνοιξε χωρίς να έχει εγκατασταθεί. Πατήστε για να μάθετε περισσότερα."</string>      <string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Μετάβ. σε πρόγ. περ."</string> +    <string name="go_to_web" msgid="1106022723459948514">"Μετάβαση στον ιστό"</string>      <string name="mobile_data" msgid="7094582042819250762">"Δεδομένα κινητής τηλεφωνίας"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Το Wi-Fi είναι ανενεργό"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 0a2fec28dcef..65034700ec21 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"open camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>      <string name="app_info" msgid="6856026610594615344">"App info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 7b1021230379..9e4081c71845 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"open camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>      <string name="app_info" msgid="6856026610594615344">"App info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 0a2fec28dcef..65034700ec21 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"open camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>      <string name="app_info" msgid="6856026610594615344">"App info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 0a2fec28dcef..65034700ec21 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"open camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>      <string name="app_info" msgid="6856026610594615344">"App info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 259d3cab5439..40205b942caa 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"open camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>      <string name="cancel" msgid="6442560571259935130">"Cancel"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to learn more."</string>      <string name="app_info" msgid="6856026610594615344">"App info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 33177f0dd2d2..d4adfdcb42d9 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selecciona el nuevo diseño de la tarea."</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensajes de ayuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor de huellas digitales"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícono de huella digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Autenticando tu rostro…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícono de rostro"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Sugerencias"</string>      <string name="instant_apps" msgid="6647570248119804907">"Apps instantáneas"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Las Apps instantáneas no requieren instalación."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"La app se abrió sin instalarse."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"La app se abrió sin instalarse. Presiona para obtener más información."</string>      <string name="app_info" msgid="6856026610594615344">"Información de apps"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index c80c495020a0..00c179cee16f 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -19,7 +19,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="7164937344850004466">"IU del sistema"</string> +    <string name="app_label" msgid="7164937344850004466">"UI del sistema"</string>      <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>      <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Quitar de la lista"</string>      <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string> @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar diseño de tarea nueva"</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensaje de ayuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor de huellas digitales"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icono de huella digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Buscando tu cara…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icono de cara"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string> @@ -567,13 +563,13 @@      <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>      <string name="output_service_wifi" msgid="3749735218931825054">"Wi‑Fi"</string>      <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth y Wi‑Fi"</string> -    <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de IU del sistema"</string> +    <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de UI del sistema"</string>      <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de batería insertado"</string>      <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar el porcentaje del nivel de batería en el icono de la barra de estado cuando no se esté cargando"</string>      <string name="quick_settings" msgid="10042998191725428">"Ajustes rápidos"</string>      <string name="status_bar" msgid="4877645476959324760">"Barra de estado"</string>      <string name="overview" msgid="4018602013895926956">"Aplicaciones recientes"</string> -    <string name="demo_mode" msgid="2532177350215638026">"Modo de demostración de IU del sistema"</string> +    <string name="demo_mode" msgid="2532177350215638026">"Modo de demostración de UI del sistema"</string>      <string name="enable_demo_mode" msgid="4844205668718636518">"Habilitar modo de demostración"</string>      <string name="show_demo_mode" msgid="2018336697782464029">"Mostrar modo de demostración"</string>      <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string> @@ -590,12 +586,12 @@      <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Zona Wi-Fi"</string>      <string name="accessibility_managed_profile" msgid="6613641363112584120">"Perfil de trabajo"</string>      <string name="tuner_warning_title" msgid="7094689930793031682">"Diversión solo para algunos"</string> -    <string name="tuner_warning" msgid="8730648121973575701">"El configurador de IU del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string> +    <string name="tuner_warning" msgid="8730648121973575701">"El configurador de UI del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>      <string name="tuner_persistent_warning" msgid="8597333795565621795">"Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>      <string name="got_it" msgid="2239653834387972602">"Entendido"</string> -    <string name="tuner_toast" msgid="603429811084428439">"¡Enhorabuena! El configurador de IU del sistema se ha añadido a Ajustes"</string> +    <string name="tuner_toast" msgid="603429811084428439">"¡Enhorabuena! El configurador de UI del sistema se ha añadido a Ajustes"</string>      <string name="remove_from_settings" msgid="8389591916603406378">"Quitar de Ajustes"</string> -    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quitar el configurador de IU del sistema de Ajustes y dejar de utilizar sus funciones?"</string> +    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quitar el configurador de UI del sistema de Ajustes y dejar de utilizar sus funciones?"</string>      <string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>      <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>      <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Sugerencias"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplicaciones Instantáneas"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"No es necesario instalar las Aplicaciones Instantáneas."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"La aplicación se abre sin necesidad de instalarla."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"La aplicación se abre sin necesidad de instalarla. Toca para obtener más información."</string>      <string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> ‑ <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index d4923e2a67ee..246f1f82fef3 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ava kaamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Uue toimingu paigutuse valimine"</string>      <string name="cancel" msgid="6442560571259935130">"Tühista"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Abisõnumi ala"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Kinnita"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Puudutage sõrmejäljeandurit"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Sõrmejälje ikoon"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Otsitakse teid …"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Näoikoon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth on ühendatud."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Salvestusruum"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Vihjed"</string>      <string name="instant_apps" msgid="6647570248119804907">"Installimata avatavad rakendused"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Installimata avatavaid rakendusi pole vaja installida."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Rakendus <xliff:g id="APP">%1$s</xliff:g> töötab"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Rakendus avati installimata."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Rakendus avati installimata. Lisateabe saamiseks puudutage."</string>      <string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ava brauser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Avage veebis"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobiilne andmeside"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"WiFi on välja lülitatud"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 379683fa35c4..b73946efa1fa 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Hautatu zereginen diseinua"</string>      <string name="cancel" msgid="6442560571259935130">"Utzi"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Laguntza-mezuaren eremua"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Berretsi"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sakatu hatz-marken sentsorea"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Hatz-markaren ikonoa"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Zure bila…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Aurpegiaren ikonoa"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Aholkuak"</string>      <string name="instant_apps" msgid="6647570248119804907">"Zuzeneko aplikazioak"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Zuzeneko aplikazioak ez dira instalatu behar."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen ari da"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Ezer instalatu gabe ireki da aplikazioa."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ezer instalatu gabe ireki da aplikazioa. Sakatu informazio gehiago lortzeko."</string>      <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Joan arakatzailera"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Joan sarera"</string>      <string name="mobile_data" msgid="7094582042819250762">"Datu-konexioa"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi konexioa desaktibatuta dago"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index cafba14ca4ed..3997f1aa9ce5 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -47,7 +47,7 @@      <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>      <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>      <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string> -    <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بیصدا"</string> +    <string name="status_bar_settings_mute_label" msgid="554682549917429396">"صامت"</string>      <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>      <string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلانها"</string>      <string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string> @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"باز کردن دوربین"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"انتخاب طرحبندی جدید کار"</string>      <string name="cancel" msgid="6442560571259935130">"لغو"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"بخش پیام راهنما"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تأیید"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"حسگر اثر انگشت را لمس کنید"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"نماد اثر انگشت"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"درحال جستجوی شما…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"نماد چهره"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحههای کوچک تا بزرگ."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوتوث متصل است."</string> @@ -545,14 +541,14 @@      <string name="ring_toggle_title" msgid="3281244519428819576">"تماسها"</string>      <string name="volume_ringer_status_normal" msgid="4273142424125855384">"زنگ زدن"</string>      <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"لرزش"</string> -    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"بیصدا"</string> +    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"صامت"</string>      <string name="qs_status_phone_vibrate" msgid="204362991135761679">"تلفن در حالت لرزش است"</string>      <string name="qs_status_phone_muted" msgid="5437668875879171548">"تلفن بیصدا است"</string>      <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. برای باصدا کردن ضربه بزنید."</string>      <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string> -    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. برای بیصدا کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string> +    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری صامت شود."</string>      <string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string> -    <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. برای بیصدا کردن ضربه بزنید."</string> +    <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. برای صامت کردن ضربه بزنید."</string>      <string name="volume_ringer_hint_mute" msgid="9199811307292269601">"صامت کردن"</string>      <string name="volume_ringer_hint_unmute" msgid="6602880133293060368">"باصدا کردن"</string>      <string name="volume_ringer_hint_vibrate" msgid="4036802135666515202">"لرزش"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"فضای ذخیرهسازی"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"نکات"</string>      <string name="instant_apps" msgid="6647570248119804907">"برنامههای فوری"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"برنامههای فوری نیاز به نصب ندارند."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> درحال اجرا"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"برنامه بدون نصب شدن باز شد."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"برنامه بدون نصب شدن باز شد. برای اطلاعات بیشتر ضربه بزنید."</string>      <string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string> -    <string name="go_to_web" msgid="2650669128861626071">"رفتن به مرورگر"</string> +    <string name="go_to_web" msgid="1106022723459948514">"رفتن به وب"</string>      <string name="mobile_data" msgid="7094582042819250762">"داده تلفن همراه"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi خاموش است"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 311d3bdef685..6e8cb4c3cb3f 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Valitse uusi tehtävien asettelu"</string>      <string name="cancel" msgid="6442560571259935130">"Peruuta"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Ohjeviestialue"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Vahvista"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Kosketa sormenjälkitunnistinta"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Sormenjälkikuvake"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Etsitään kasvoja…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Kasvokuvake"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Tallennustila"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Vihjeet"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Pikasovelluksia ei tarvitse asentaa."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> on käynnissä"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Sovellus avattiin ilman asennusta."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Sovellus avattiin ilman asennusta. Katso lisätietoja napauttamalla."</string>      <string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Siirry selaimeen"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Avaa verkossa"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobiilitiedonsiirto"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi on pois käytöstä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 253496159e2a..f6d66b7301be 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Sélectionner un nouveau format de tâche"</string>      <string name="cancel" msgid="6442560571259935130">"Annuler"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zone de message d\'aide"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmer"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touchez le capteur d\'empreintes digitales"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icône d\'empreinte digitale"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Recherche de votre visage…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icône de visage"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Stockage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Conseils"</string>      <string name="instant_apps" msgid="6647570248119804907">"Applications instantanées"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Les applications instantanées ne nécessitent pas d\'installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Application ouverte sans avoir été installée."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Application ouverte sans avoir été installée. Touchez ici pour en savoir plus."</string>      <string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ouvrir le navigateur"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Accéder au Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Données cellulaires"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> : <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Le Wi-Fi est désactivé"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index a82ae24ae9f2..326b7c75a9c9 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ouvrir l\'appareil photo"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Sélectionner un nouveau plan de tâche"</string>      <string name="cancel" msgid="6442560571259935130">"Annuler"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zone de message d\'aide"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmer"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Appuyez sur le lecteur d\'empreinte digitale"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icône d\'empreinte digitale"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Recherche de votre visage…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icône représentant un visage"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Astuces"</string>      <string name="instant_apps" msgid="6647570248119804907">"Applis instantanées"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Les applis instantanées ne nécessitent pas d\'installation."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Vous pouvez ouvrir cette application sans l\'installer."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Vous pouvez ouvrir cette application sans l\'installer. Appuyez pour en savoir plus."</string>      <string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Accéder au navigateur"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Accéder au site Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Données mobiles"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi désactivé"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index d987c568f15c..192c132dee18 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar novo deseño de tarefas"</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensaxes de axuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca o sensor de impresión dixital"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona de impresión dixital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Buscándote…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona de cara"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidade"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilidade co tamaño da pantalla."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Consellos"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplicacións instantáneas"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"As aplicacións instantáneas non precisan instalación."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Estase executando <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Abriuse a aplicación sen ter que instalala."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Abriuse a aplicación sen ter que instalala. Tocar para obter máis información."</string>      <string name="app_info" msgid="6856026610594615344">"Info. da aplicación"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ir ao navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Acceder á web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Datos móbiles"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>-<xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"A wifi está desactivada"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 70a75fcd58f6..f3922681e47f 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"કૅમેરો ખોલો"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"નવું કાર્ય લેઆઉટ પસંદ કરો"</string>      <string name="cancel" msgid="6442560571259935130">"રદ કરો"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"સહાય સંદેશનું ક્ષેત્ર"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"કન્ફર્મ કરો"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ફિંગરપ્રિન્ટનું આઇકન"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"તમારા માટે શોધી રહ્યાં છે..."</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ચહેરા આઇકન"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"સુસંગતતા ઝૂમ બટન."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"નાનીથી મોટી સ્ક્રીન પર ઝૂમ કરો."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"બ્લૂટૂથ કનેક્ટ થયું."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"સ્ટોરેજ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"હિન્ટ"</string>      <string name="instant_apps" msgid="6647570248119804907">"ઝટપટ ઍપ્લિકેશનો"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ઝટપટ ઍપ્લિકેશનો માટે ઇન્સ્ટૉલેશનની જરૂર નથી."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string> -    <string name="go_to_web" msgid="2650669128861626071">"બ્રાઉઝર પર જાઓ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"વેબ પર જાઓ"</string>      <string name="mobile_data" msgid="7094582042819250762">"મોબાઇલ ડેટા"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"વાઇ-ફાઇ બંધ છે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index e098657fba1b..87952643c96a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"नया कार्य लेआउट चुनें"</string>      <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"सहायता का मैसेज दिखाने की जगह"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"पुष्टि करें"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फ़िंगरप्रिंट सेंसर को छुएं"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फ़िंगरप्रिंट आइकॉन"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"आपको पहचान रहा है…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"चेहरे का आइकॉन"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्क्रीन पर ज़ूम करें."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"जगह"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"संकेत"</string>      <string name="instant_apps" msgid="6647570248119804907">"इंस्टेंट ऐप"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"झटपट ऐप्स के लिए इंस्टॉलेशन ज़रूरी नहीं है."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> चल रहा है"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है. ज़्यादा जानने के लिए टैप करें."</string>      <string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ब्राउज़र पर जाएं"</string> +    <string name="go_to_web" msgid="1106022723459948514">"वेब पर जाएं"</string>      <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"वाई-फ़ाई बंद है"</string> diff --git a/packages/SystemUI/res/values-hi/strings_car.xml b/packages/SystemUI/res/values-hi/strings_car.xml index 8820046cf11f..3beada5c174e 100644 --- a/packages/SystemUI/res/values-hi/strings_car.xml +++ b/packages/SystemUI/res/values-hi/strings_car.xml @@ -20,8 +20,7 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="car_guest" msgid="3738772168718508650">"मेहमान"</string> -    <!-- no translation found for start_guest_session (7055742120180595689) --> -    <skip /> +    <string name="start_guest_session" msgid="7055742120180595689">"मेहमान मोड"</string>      <string name="car_add_user" msgid="5245196248349230898">"उपयोगकर्ता जोड़ें"</string>      <string name="car_new_user" msgid="8142927244990323906">"नया उपयोगकर्ता"</string>      <string name="user_add_user_message_setup" msgid="1791011504259527329">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं तो, उस व्यक्ति को अपनी जगह सेट करनी होती है."</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 53250db5ba7e..b6fa4f58cce5 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"otvaranje fotoaparata"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi izgled zadataka"</string>      <string name="cancel" msgid="6442560571259935130">"Odustani"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Područje poruke za pomoć"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdi"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor otiska prsta"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otiska prsta"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth povezan."</string> @@ -835,9 +831,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Savjeti"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije nije potrebno instalirati."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Izvodi se aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je otvorena bez instaliranja."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je otvorena bez instaliranja. Dodirnite da biste saznali više."</string>      <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Otvori preglednik"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Prijeđi na web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index ee8ff0b07018..9076379fc70b 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"kamera megnyitása"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Új feladatelrendezés kiválasztása"</string>      <string name="cancel" msgid="6442560571259935130">"Mégse"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Súgószöveg területe"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Megerősítés"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Érintse meg az ujjlenyomat-érzékelőt"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ujjlenyomat ikonja"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Keresem az Ön arcát…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Arcikon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth csatlakoztatva."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Tárhely"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Tippek"</string>      <string name="instant_apps" msgid="6647570248119804907">"Azonnali alkalmazások"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Az azonnali alkalmazásokat nem kell telepíteni."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás jelenleg fut"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Az alkalmazás telepítés nélkül lett megnyitva."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Az alkalmazás telepítés nélkül lett megnyitva. Ha további információra van szüksége, koppintson ide."</string>      <string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ugrás a böngészőbe"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Tovább az internetre"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobiladatok"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"A Wi-Fi ki van kapcsolva"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index bb8af5424f6d..54401f53347d 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Ընտրել առաջադրանքի նոր դասավորություն"</string>      <string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Օգնության հաղորդագրության դաշտ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Հաստատել"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Հպեք մատնահետքերի սկաներին"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Մատնահետքի պատկերակ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Դեմքի ճանաչում…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Դեմքի պատկերակ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string> @@ -588,12 +584,12 @@      <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Թեժ կետ"</string>      <string name="accessibility_managed_profile" msgid="6613641363112584120">"Աշխատանքային պրոֆիլ"</string>      <string name="tuner_warning_title" msgid="7094689930793031682">"Զվարճանք մեկ՝ որոշակի մարդու համար"</string> -    <string name="tuner_warning" msgid="8730648121973575701">"Համակարգի ՕՄ-ի ընդունիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string> +    <string name="tuner_warning" msgid="8730648121973575701">"Համակարգի ՕՄ-ի կարգավորիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>      <string name="tuner_persistent_warning" msgid="8597333795565621795">"Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>      <string name="got_it" msgid="2239653834387972602">"Եղավ"</string> -    <string name="tuner_toast" msgid="603429811084428439">"Համակարգի ՕՄ-ի ընդունիչը ավելացվել է կարգավորումներին"</string> +    <string name="tuner_toast" msgid="603429811084428439">"Համակարգի ՕՄ-ի կարգավորիչը ավելացվել է կարգավորումներին"</string>      <string name="remove_from_settings" msgid="8389591916603406378">"Հեռացնել կարգավորումներից"</string> -    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի ընդունիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string> +    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի կարգավորիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string>      <string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>      <string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>      <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Տարածք"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Հուշումներ"</string>      <string name="instant_apps" msgid="6647570248119804907">"Ակնթարթային հավելվածներ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Ակնթարթային հավելվածները տեղադրում չեն պահանջում։"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն աշխատում է"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Հավելվածը բացվել է առանց տեղադրման։"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Հավելվածը բացվել է առանց տեղադրման։ Հպեք՝ ավելին իմանալու համար։"</string>      <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Անցնել դիտարկիչ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Բացեք համացանցում"</string>      <string name="mobile_data" msgid="7094582042819250762">"Բջջային ինտերնետ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi-ն անջատված է"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 2b387021a65e..247415827c34 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Pilih tata letak tugas baru"</string>      <string name="cancel" msgid="6442560571259935130">"Batal"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Area pesan bantuan"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Konfirmasi"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sentuh sensor sidik jari"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon sidik jari"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Mencari wajah Anda…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikon wajah"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tersambung."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Penyimpanan"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Petunjuk"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplikasi Instan"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikasi instan tidak perlu diinstal."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikasi dapat dibuka tanpa perlu diinstal."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikasi dapat dibuka tanpa perlu diinstal. Tap untuk mempelajari lebih lanjut."</string>      <string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Buka browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Buka di web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Data seluler"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi nonaktif"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 184ebed8d275..c2a020b89e3f 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"opna myndavél"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Velja nýtt útlit verkefna"</string>      <string name="cancel" msgid="6442560571259935130">"Hætta við"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Svæði hjálparskilaboða"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Staðfesta"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Snertu fingrafaralesarann"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingrafaratákn"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Leitar að þér ..."</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Andlitstákn"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Hnappur fyrir samhæfisaðdrátt."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aðlaga forrit fyrir lítinn skjá að stærri skjá."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tengt."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Geymslurými"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Vísbendingar"</string>      <string name="instant_apps" msgid="6647570248119804907">"Skyndiforrit"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Skyndiforrit þurfa ekki uppsetningu."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Forrit opnað án þess að vera uppsett."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Forrit opnað án þess að vera uppsett. Ýttu til að fá frekari upplýsingar."</string>      <string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Opna vafra"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Fara á vefinn"</string>      <string name="mobile_data" msgid="7094582042819250762">"Farsímagögn"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Slökkt á Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 9a6e38b61eb4..aefaa6dff4b8 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Seleziona un nuovo layout per le attività"</string>      <string name="cancel" msgid="6442560571259935130">"Annulla"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Area dei messaggi di assistenza"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confermo"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Tocca il sensore di impronte digitali"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona dell\'impronta digitale"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"In attesa del volto…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona volto"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Spazio di archiviazione"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Suggerimenti"</string>      <string name="instant_apps" msgid="6647570248119804907">"App istantanee"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Le app istantanee non richiedono l\'installazione."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"App <xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App aperta senza essere stata installata."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App aperta senza essere stata installata. Tocca per avere ulteriori informazioni."</string>      <string name="app_info" msgid="6856026610594615344">"Informazioni app"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Vai al browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Vai sul Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dati mobili"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi disattivato"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index cf1d3370a5ac..b83f5dff6736 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"בחר פריסה חדשה להצגת משימות"</string>      <string name="cancel" msgid="6442560571259935130">"ביטול"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"אזור הודעת עזרה"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"אישור"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"יש לגעת בחיישן טביעות האצבע"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"סמל טביעת אצבע"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"מחפש אותך…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"סמל הפנים"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth מחובר."</string> @@ -841,9 +837,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"אחסון"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"טיפים"</string>      <string name="instant_apps" msgid="6647570248119804907">"אפליקציות אינסטנט"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"אפליקציות אינסטנט לא דורשות התקנה."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> פועלת"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"האפליקציה נפתחת בלי התקנה."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"האפליקציה נפתחת בלי התקנה. אפשר להקיש כדי לקבל מידע נוסף."</string>      <string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string> -    <string name="go_to_web" msgid="2650669128861626071">"מעבר אל הדפדפן"</string> +    <string name="go_to_web" msgid="1106022723459948514">"התחבר לאינטרנט"</string>      <string name="mobile_data" msgid="7094582042819250762">"נתונים סלולריים"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi כבוי"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index f6674d60efae..e5b0a2b7e766 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"カメラを起動"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"新しいタスクレイアウトの選択"</string>      <string name="cancel" msgid="6442560571259935130">"キャンセル"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ヘルプ メッセージ領域"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"指紋認証センサーをタップしてください"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋アイコン"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"顔を認証しています…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"顔アイコン"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetoothに接続済み。"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ストレージ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ヒント"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps はインストールせずに利用できます。"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> を実行中"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"アプリをインストールせずに開きました。"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"アプリをインストールせずに開きました。詳細を見るにはタップしてください。"</string>      <string name="app_info" msgid="6856026610594615344">"アプリ情報"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ブラウザに移動"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ウェブページを開く"</string>      <string name="mobile_data" msgid="7094582042819250762">"モバイルデータ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi は OFF です"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 26de531591b6..19e9f471e226 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"კამერის გახსნა"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ახალი ამოცანის განლაგების არჩევა"</string>      <string name="cancel" msgid="6442560571259935130">"გაუქმება"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"დამხმარე შეტყობინების არე"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"დადასტურება"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"შეეხეთ თითის ანაბეჭდის სენსორს"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"თითის ანაბეჭდის ხატულა"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"მიმდინარეობს თქვენი ძიება…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"სახის ხატულა"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"მეხსიერება"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"მინიშნებები"</string>      <string name="instant_apps" msgid="6647570248119804907">"მყისიერი აპები"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"მყისიერი აპები ინსტალაციას არ საჭიროებს."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"აპი გაიხსნა ინსტალაციის გარეშე."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"აპი გაიხსნა ინსტალაციის გარეშე. შეეხეთ მეტის გასაგებად."</string>      <string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ბრაუზერზე გადასვლა"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ვებზე გადასვლა"</string>      <string name="mobile_data" msgid="7094582042819250762">"მობილური ინტერნეტი"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi გამორთულია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index d06c0f54981f..15f8cd56f876 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"камераны ашу"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Жаңа тапсырма пішімін таңдау"</string>      <string name="cancel" msgid="6442560571259935130">"Бас тарту"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Анықтама хабары аумағы"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Растау"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Саусақ ізін оқу сканерін түртіңіз"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Саусақ ізі белгішесі"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Бет ізделуде…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Бет белгішесі"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Үйлесімділік ұлғайту түймесі."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Үлкендеу экранда кішірейту."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth қосылған."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Жад"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Кеңестер"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Лездік қолданбаларды орнатудың қажеті жоқ."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> іске қосулы"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Қолданба орнатылмай-ақ ашылды."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Қолданба орнатылмай-ақ ашылды. Толығырақ мәлімет алу үшін түртіңіз."</string>      <string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Браузерге өту"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Вебке өту"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобильдік деректер"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi өшірулі"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index bf9ad75932f8..af8d4ceefc5f 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"បើកម៉ាស៊ីនថត"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ជ្រើសប្លង់ភារកិច្ចថ្មី"</string>      <string name="cancel" msgid="6442560571259935130">"បោះបង់"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"តំបន់សារជំនួយ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"បញ្ជាក់"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ប៉ះឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"រូបតំណាងស្នាមម្រាមដៃ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"កំពុងស្វែងរកអ្នក…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"រូបផ្ទៃមុខ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុងពង្រីកត្រូវគ្នា។"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួមអេក្រង់ពីទៅធំ"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បានតភ្ជាប់ប៊្លូធូស។"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ទំហំផ្ទុក"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ការសម្រួល"</string>      <string name="instant_apps" msgid="6647570248119804907">"កម្មវិធីប្រើភ្លាមៗ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"កម្មវិធីប្រើភ្លាមៗមិនតម្រូវឲ្យមានការដំឡើងទេ។"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការ"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"កម្មវិធីត្រូវបានបើកដោយមិនចាំបាច់ដំឡើង។"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"កម្មវិធីត្រូវបានបើកដោយមិនចាំបាច់ដំឡើង។ ចុចដើម្បីស្វែងយល់បន្ថែម។"</string>      <string name="app_info" msgid="6856026610594615344">"ព័ត៌មានកម្មវិធី"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ចូលទៅកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ចូលទៅកាន់បណ្តាញ"</string>      <string name="mobile_data" msgid="7094582042819250762">"ទិន្នន័យទូរសព្ទចល័ត"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi បានបិទ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 482343721f44..ac36e73d602d 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ಹೊಸ ಕಾರ್ಯ ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>      <string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ಸಹಾಯ ಸಂದೇಶ ಪ್ರದೇಶ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ದೃಢೀಕರಿಸಿ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ನಿಮಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ಮುಖದ ಐಕಾನ್"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ಸಂಗ್ರಹಣೆ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ಸುಳಿವುಗಳು"</string>      <string name="instant_apps" msgid="6647570248119804907">"ತತ್ಕ್ಷಣ ಆಪ್ಗಳು"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ತತ್ಕ್ಷಣ ಆಪ್ಗಳಿಗೆ ಸ್ಥಾಪನೆಯ ಅಗತ್ಯವಿಲ್ಲ."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ಬ್ರೌಸರ್ಗೆ ಹೋಗಿ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ವೆಬ್ಗೆ ಹೋಗಿ"</string>      <string name="mobile_data" msgid="7094582042819250762">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"ವೈ-ಫೈ ಆಫ್ ಆಗಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 10c1e282b1d9..1e2ab424832e 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"카메라 열기"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"새 작업 레이아웃 선택"</string>      <string name="cancel" msgid="6442560571259935130">"취소"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"도움말 메시지 영역"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"확인"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"지문 센서를 터치하세요."</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"지문 아이콘"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"찾는 중..."</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"얼굴 아이콘"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"블루투스가 연결되었습니다."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"저장공간"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"힌트"</string>      <string name="instant_apps" msgid="6647570248119804907">"인스턴트 앱"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"인스턴트 앱은 설치가 필요하지 않습니다."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"설치 없이 앱이 실행되었습니다."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"설치 없이 앱이 실행되었습니다. 탭하여 자세히 알아보세요."</string>      <string name="app_info" msgid="6856026610594615344">"앱 정보"</string> -    <string name="go_to_web" msgid="2650669128861626071">"브라우저로 이동"</string> +    <string name="go_to_web" msgid="1106022723459948514">"웹으로 이동"</string>      <string name="mobile_data" msgid="7094582042819250762">"모바일 데이터"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi가 사용 중지됨"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index a0e630afaffa..585e2900eb4b 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"камераны ачуу"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Жаңы тапшырманын планын тандаңыз"</string>      <string name="cancel" msgid="6442560571259935130">"Жокко чыгаруу"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Жардам билдирүүсү"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Ырастоо"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Манжа изинин сенсорун басыңыз"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Манжа изинин сүрөтчөсү"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Жүзүңүз изделүүдө…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Жүздүн сүрөтчөсү"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Масштабды сыйыштыруу баскычы."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Кичинекейди чоң экранга масштабдоо."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth байланышта"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Сактагыч"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Кеңештер"</string>      <string name="instant_apps" msgid="6647570248119804907">"Ыкчам ачылуучу колдонмолор"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Ыкчам ачылуучу колдонмолорду орнотуу талап кылынбайт."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Колдонмо орнотулбастан ачылды."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Колдонмо орнотулбастан ачылды. Толугураак маалымат алуу үчүн таптап коюңуз."</string>      <string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Серепчиге өтүү"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Интернетке өтүү"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобилдик Интернет"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi өчүк"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 3cc1ac1e857b..0952df4c1c7f 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ເປີດກ້ອງ"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ເລືອກແຜນຜັງໜ້າວຽກໃໝ່"</string>      <string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ຊ່ວຍພື້ນທີ່ຂໍ້ຄວາມ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ຢືນຢັນ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ໄອຄອນລາຍນິ້ວມື"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ກຳລັງຊອກຫາທ່ານ…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ໄອຄອນໃບໜ້າ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ບ່ອນເກັບຂໍ້ມູນ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ຄຳໃບ້"</string>      <string name="instant_apps" msgid="6647570248119804907">"ອິນສະແຕນແອັບ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ອິນສະແຕນແອັບບໍ່ຈຳເປັນຕ້ອງມີການຕິດຕັ້ງ."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກຢູ່"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"ເປີດແອັບໂດຍບໍ່ມີການຕິດຕັ້ງແລ້ວ."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ເປີດແອັບໂດຍບໍ່ມີການຕິດຕັ້ງແລ້ວ. ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>      <string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ໄປທີ່ໂປຣແກຣມທ່ອງເວັບ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ໄປທີ່ເວັບ"</string>      <string name="mobile_data" msgid="7094582042819250762">"ອິນເຕີເນັດມືຖື"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ປິດຢູ່"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index e7d423b04913..ac6cfc79216c 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Pasirinkti naują užduoties išdėstymą"</string>      <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Pagalbos pranešimo sritis"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Patvirtinkite"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Palieskite kontrolinio kodo jutiklį"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Kontrolinio kodo piktograma"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ieškoma jūsų…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Veido piktograma"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"„Bluetooth“ prijungtas."</string> @@ -841,9 +837,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Saugykla"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Užuominos"</string>      <string name="instant_apps" msgid="6647570248119804907">"Akimirksniu įkeliamos programos"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Akimirksniu įkeliamų programų nereikia įdiegti."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Programa „<xliff:g id="APP">%1$s</xliff:g>“ paleista"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Programa atidaryta jos neįdiegus."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Programa atidaryta jos neįdiegus. Palieskite, kad sužinotumėte daugiau."</string>      <string name="app_info" msgid="6856026610594615344">"Programos informacija"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Eiti į naršyklę"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Eiti į žiniatinklį"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilieji duomenys"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>–<xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"„Wi-Fi“ išjungtas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4fd96680010a..01e2e398945d 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"atvērt kameru"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Atlasiet jaunu uzdevumu izkārtojumu"</string>      <string name="cancel" msgid="6442560571259935130">"Atcelt"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Palīdzības ziņojuma apgabals"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Apstiprināt"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Pieskarieties pirksta nospieduma sensoram"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Pirksta nospieduma ikona"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Notiek jūsu sejas meklēšana…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Sejas ikona"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth savienojums ir izveidots."</string> @@ -835,9 +831,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Krātuve"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Padomi"</string>      <string name="instant_apps" msgid="6647570248119804907">"Tūlītējās lietotnes"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Tūlītējām lietotnēm nav nepieciešama instalēšana."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Lietotne <xliff:g id="APP">%1$s</xliff:g> darbojas"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Lai atvērtu šo lietotni, tā nav jāinstalē."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Lai atvērtu šo lietotni, tā nav jāinstalē. Pieskarieties, lai uzzinātu vairāk."</string>      <string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Atvērt pārlūku"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Pāriet uz tīmekli"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilie dati"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ir izslēgts"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index e29e649524c7..8b4b4584bab7 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Изберете нов распоред на задача"</string>      <string name="cancel" msgid="6442560571259935130">"Откажи"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област за пораки за помош"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потврди"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Допрете го сензорот за отпечатоци"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона за отпечатоци"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ве бараме вас…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона за лице"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Капацитет"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Совети"</string>      <string name="instant_apps" msgid="6647570248119804907">"Инстант апликации"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликациите нема потреба да се инсталираат."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Се извршува <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Апликацијата беше отворена без да се инсталира."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Апликацијата беше отворена без да се инсталира. Допрете за да дознаете повеќе."</string>      <string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Одете на прелистувач"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Одете на интернет"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобилен интернет"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi е исклучено"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 8d4ce0a45a47..fc32b88d2f15 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"പുതിയ ടാസ്ക് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>      <string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"സഹായ സന്ദേശ ഏരിയ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"സ്ഥിരീകരിക്കുക"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"വിരലടയാള സെൻസർ സ്പർശിക്കുക"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"വിരലടയാള ഐക്കൺ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"നിങ്ങൾക്കായി തിരയുന്നു…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"മുഖത്തിന്റെ ഐക്കൺ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്റ്റുചെയ്തു."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"സ്റ്റോറേജ്"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"സൂചനകൾ"</string>      <string name="instant_apps" msgid="6647570248119804907">"ഇൻസ്റ്റന്റ് ആപ്പ്"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ഇൻസ്റ്റന്റ് ആപ്പിന് ഇൻസ്റ്റലേഷൻ ആവശ്യമില്ല."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ബ്രൗസറിലേക്ക് പോവുക"</string> +    <string name="go_to_web" msgid="1106022723459948514">"വെബിൽ പോവുക"</string>      <string name="mobile_data" msgid="7094582042819250762">"മൊബൈൽ ഡാറ്റ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"വൈഫൈ ഓഫാണ്"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 421c6d81cc3e..331e9b78913a 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -101,16 +101,12 @@      <string name="camera_label" msgid="7261107956054836961">"камер нээх"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Шинэ ажиллах талбарыг сонгоно уу"</string>      <string name="cancel" msgid="6442560571259935130">"Цуцлах"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Тусламжийн зурвасын хэсэг"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Баталгаажуулах"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Хурууны хээ мэдрэгчид хүрэх"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Хурууны хээний дүрс тэмдэг"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Таныг хайж байна…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Царайны дүрс тэмдэг"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth холбогдсон."</string> @@ -827,9 +823,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Хадгалах сан"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Заавар"</string>      <string name="instant_apps" msgid="6647570248119804907">"Шуурхай апп"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Шуурхай аппыг суулгах шаардлагагүй."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g>-г ажиллуулж байна"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Аппыг суулгахгүйгээр нээсэн."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Аппыг суулгахгүйгээр нээсэн. Нэмэлт мэдээлэл авахын тулд товшино уу."</string>      <string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Хөтчид очих"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Вэбэд очих"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобайл дата"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi унтраалттай байна"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 589ac527cc5d..33761caaaa75 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"नवीन कार्य लेआउट निवडा"</string>      <string name="cancel" msgid="6442560571259935130">"रद्द करा"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"मदत मेसेज परिसर"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"खात्री करा"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिंट आयकन"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"तुमच्यासाठी शोधत आहे…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"चेहरा आयकन"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्या स्क्रीनवर झूम करा."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट केले."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"स्टोरेज"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"सूचना"</string>      <string name="instant_apps" msgid="6647570248119804907">"इन्सटंट अॅप्स"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"इन्सटंट अॅप्सना स्थापनेची आवश्यकता नसते."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ब्राउझरवर जा"</string> +    <string name="go_to_web" msgid="1106022723459948514">"वेबवर जा"</string>      <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"वाय-फाय बंद आहे"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index f13a8649af4d..d6a71ef92706 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Pilih reka letak tugas baharu"</string>      <string name="cancel" msgid="6442560571259935130">"Batal"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Bahagian mesej bantuan"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Sahkan"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sentuh penderia cap jari"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon cap jari"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Mencari anda…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikon wajah"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth disambungkan."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storan"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Pembayang"</string>      <string name="instant_apps" msgid="6647570248119804907">"Apl Segera"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Apl segera tidak memerlukan pemasangan."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> sedang berjalan"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Apl dibuka tanpa dipasang."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Apl dibuka tanpa dipasang. Ketik untuk mengetahui lebih lanjut."</string>      <string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Pergi ke penyemak imbas"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Pergi ke web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Data mudah alih"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi dimatikan"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index b9f4cc736bfb..2a6e3c25e97b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"အလုပ်သစ်စီစဥ်မှုကို ရွေးပါ။"</string>      <string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"အကူအညီမက်ဆေ့ဂျ် နေရာ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"အတည်ပြုပါ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"လက်ဗွေ သင်္ကေတ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"သင့်ကို ရှာဖွေနေသည်…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"မျက်နှာသင်္ကေတ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံဝင်ခွင်ကျ ဇူးမ်ခလုတ်"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ ဇူးမ်ဆွဲခြင်း"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"သိုလှောင်မှုများ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"အရိပ်အမြွက်များ"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ချက်ခြင်းသုံးအက်ပ်များကို ထည့်သွင်းစရာမလိုပါ။"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> လုပ်ဆောင်နေသည်"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"အက်ပ်ကိုမထည့်သွင်းဘဲ ဖွင့်ထားသည်။"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"အက်ပ်ကိုမထည့်သွင်းဘဲ ဖွင့်ထားသည်။ ပိုမိုလေ့လာရန် တို့ပါ။"</string>      <string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ဘရောင်ဇာသို့ သွားပါ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ဝဘ်သို့ သွားရန်"</string>      <string name="mobile_data" msgid="7094582042819250762">"မိုဘိုင်းဒေတာ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> —<xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ကို ပိတ်ထားသည်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index cb070e6e0dc0..d90eba3f2b9d 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Velg en ny utforming for oppgaver"</string>      <string name="cancel" msgid="6442560571259935130">"Avbryt"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område for hjelpemelding"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekreft"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Trykk på fingeravtrykkssensoren"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeravtrykk"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ser etter deg …"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansiktikon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hint"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Du trenger ikke å installere instant-apper."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Appen ble åpnet uten at den ble installert."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Appen ble åpnet uten at den ble installert. Trykk for å finne ut mer."</string>      <string name="app_info" msgid="6856026610594615344">"Info om appen"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Gå til nettleser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Gå til nettstedet"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er av"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index d922e717e63c..4e3cdddee65f 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"नयाँ कार्य लेआउट चयन गर्नुहोस्"</string>      <string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"मद्दतसम्बन्धी सन्देशको क्षेत्र"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"पुष्टि गर्नुहोस्"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिन्ट जनाउने आइकन"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"तपाईंलाई खोज्दै…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"अनुहारको आइकन"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"भण्डारण"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"सङ्केतहरू"</string>      <string name="instant_apps" msgid="6647570248119804907">"तात्कालिक अनुप्रयोगहरू"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"तात्कालिक अनुप्रयोगहरूलाई स्थापना गर्नु पर्दैन|"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"स्थापना नगरिकनै अनुप्रयोग खोलियो।"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"स्थापना नगरिकनै अनुप्रयोग खोलियो। थप जान्न ट्याप गर्नुहोस्।"</string>      <string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ब्राउजरमा जानुहोस्"</string> +    <string name="go_to_web" msgid="1106022723459948514">"वेबमा जानुहोस्"</string>      <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi‑Fi निष्क्रिय छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 8bb229af7fd7..9dda44e7c6da 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"camera openen"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Nieuwe taakindeling selecteren"</string>      <string name="cancel" msgid="6442560571259935130">"Annuleren"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Gebied voor Help-berichten"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bevestigen"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Raak de vingerafdruksensor aan"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Vingerafdrukpictogram"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Jouw gezicht zoeken…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gezichtspictogram"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-verbinding ingesteld."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Opslag"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant-apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant-apps hoeven niet te worden geïnstalleerd."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> actief"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"App geopend zonder dat deze is geïnstalleerd."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App geopend zonder dat deze is geïnstalleerd. Tik voor meer informatie."</string>      <string name="app_info" msgid="6856026610594615344">"App-info"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ga naar browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Ga naar internet"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wifi is uitgeschakeld"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index f961bde70fdb..91c62bbfd646 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"କ୍ୟାମେରା ଖୋଲନ୍ତୁ"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ନୂଆ ଟାସ୍କ ଲେଆଉଟ୍ ଚୟନ କରନ୍ତୁ"</string>      <string name="cancel" msgid="6442560571259935130">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ସାହାଯ୍ୟ ମେସେଜ୍ କ୍ଷେତ୍ର"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ନିଶ୍ଚିତ କରନ୍ତୁ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନସର୍କୁ ଛୁଅଁନ୍ତୁ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଇକନ୍"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ଆପଣଙ୍କୁ ଚିହ୍ନଟ କରୁଛି…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ମୁହଁ ଆଇକନ୍"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"କମ୍ପାଟିବିଲିଟୀ ଜୁମ୍ ବଟନ୍।"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ଜୁମ୍ କରି ସ୍କ୍ରୀନ୍କୁ ଛୋଟରୁ ବଡ଼ କରନ୍ତୁ।"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ବ୍ଲୁ-ଟୂଥ୍ ସଂଯୋଗ କରାଯାଇଛି।"</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ଷ୍ଟୋରେଜ୍"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ହିଣ୍ଟ"</string>      <string name="instant_apps" msgid="6647570248119804907">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍ ଇନଷ୍ଟଲ୍ କରିବାର ଆବଶ୍ୟକତା ନାହିଁ"</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ଆପ୍ ସୂଚନା"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ବ୍ରାଉଜର୍କୁ ଯାଆନ୍ତୁ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ୱେବକୁ ଯାଆନ୍ତୁ"</string>      <string name="mobile_data" msgid="7094582042819250762">"ମୋବାଇଲ୍ ଡାଟା"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"ୱାଇ-ଫାଇ ଅଫ୍ ଅଛି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 44785fbe82d7..96fb641f50d8 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"ਕੈਮਰਾ ਖੋਲ੍ਹੋ"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"ਨਵਾਂ ਕੰਮ ਲੇਆਉਟ ਚੁਣੋ"</string>      <string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ਮਦਦ ਸੁਨੇਹਾ ਖੇਤਰ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ਪੁਸ਼ਟੀ ਕਰੋ"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ਤੁਹਾਡੀ ਪਛਾਣ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ਅਨੁਰੂਪਤਾ ਜ਼ੂਮ ਬਟਨ।"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ਵੱਡੀ ਸਕ੍ਰੀਨ ਤੇ ਛੋਟਾ ਜ਼ੂਮ ਕਰੋ।"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ਸਟੋਰੇਜ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ਸੰਕੇਤ"</string>      <string name="instant_apps" msgid="6647570248119804907">"ਤਤਕਾਲ ਐਪਾਂ"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ਤਤਕਾਲ ਐਪਾਂ ਨੂੰ ਸਥਾਪਨਾ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।"</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ਬ੍ਰਾਊਜ਼ਰ \'ਤੇ ਜਾਓ"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ਵੈੱਬ \'ਤੇ ਜਾਓ"</string>      <string name="mobile_data" msgid="7094582042819250762">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"ਵਾਈ-ਫਾਈ ਬੰਦ ਹੈ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index a79634e9d9e9..28d24bf80d94 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"otwórz aparat"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Wybierz nowy układ zadań"</string>      <string name="cancel" msgid="6442560571259935130">"Anuluj"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Obszar komunikatu pomocy"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potwierdź"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotknij czytnika linii papilarnych"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona odcisku palca"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Szukam Cię…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona twarzy"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth połączony."</string> @@ -841,9 +837,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Pamięć wewnętrzna"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Wskazówki"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplikacje błyskawiczne"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacji błyskawicznych nie trzeba instalować."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacja została otwarta bez zainstalowania."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacja została otwarta bez zainstalowania. Kliknij, by dowiedzieć się więcej."</string>      <string name="app_info" msgid="6856026610594615344">"O aplikacji"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Otwórz przeglądarkę"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Wejdź na stronę internetową"</string>      <string name="mobile_data" msgid="7094582042819250762">"Komórkowa transmisja danych"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi jest wyłączone"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 1897d09705e9..ab0f5f2f2477 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressão digital"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Procurando você…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone facial"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Dicas"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"O app é aberto sem precisar ser instalado."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"O app é aberto sem precisar ser instalado. Toque para saber mais."</string>      <string name="app_info" msgid="6856026610594615344">"Informações do app"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 6d333b1290a3..fb0675afdefd 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo esquema de tarefa"</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressões digitais."</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"À sua procura…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone de rosto"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Sugestões"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplicações instantâneas"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"As Aplicações instantâneas não requerem instalação."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"A aplicação é aberta sem ser instalada."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"A aplicação é aberta sem ser instalada. Toque para saber mais."</string>      <string name="app_info" msgid="6856026610594615344">"Info. da aplicação"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Ir para o navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Aceder à Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desativado"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 1897d09705e9..ab0f5f2f2477 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>      <string name="cancel" msgid="6442560571259935130">"Cancelar"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressão digital"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Procurando você…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone facial"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Dicas"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"O app é aberto sem precisar ser instalado."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"O app é aberto sem precisar ser instalado. Toque para saber mais."</string>      <string name="app_info" msgid="6856026610594615344">"Informações do app"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index d174ee9b7eb5..9b5f5e13c5fa 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Selectați noul aspect pentru activitate"</string>      <string name="cancel" msgid="6442560571259935130">"Anulați"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zona mesajelor de ajutor"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmați"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Atingeți senzorul de amprente"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Pictograma amprentă"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Vă căutăm…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Pictograma chip"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceți zoom de la o imagine mai mică la una mai mare."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string> @@ -837,9 +833,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Stocare"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Indicii"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplicații instantanee"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Aplicațiile instantanee nu necesită instalare."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> rulează"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplicația a fost deschisă fără a fi instalată."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplicația a fost deschisă fără a fi instalată. Atingeți pentru a afla mai multe."</string>      <string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Accesați browserul"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Accesați pe web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Date mobile"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Conexiunea Wi-Fi este dezactivată"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 1d968e46ef51..8069317b3d99 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Выберите другой макет"</string>      <string name="cancel" msgid="6442560571259935130">"Отмена"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Справочное сообщение"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Подтвердить"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Прикоснитесь к сканеру отпечатков пальцев."</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок отпечатка пальца"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Поиск лица…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок лица"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Подсказки"</string>      <string name="instant_apps" msgid="6647570248119804907">"Приложения с мгновенным запуском"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Приложения с мгновенным запуском не требуется устанавливать."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> уже здесь!"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Приложение готово к работе, установка не требуется."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Приложение готово к работе, установка не требуется. Нажмите, чтобы узнать больше."</string>      <string name="app_info" msgid="6856026610594615344">"О приложении"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Перейти в браузер"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Перейти в браузер"</string>      <string name="mobile_data" msgid="7094582042819250762">"Моб. Интернет"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Модуль Wi-Fi отключен"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 6d3014c18fb7..8802833da72b 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"නව කාර්යය සැකැස්ම තෝරන්න"</string>      <string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"උදවු පණිවිඩ ප්රදේශය"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"තහවුරු කරන්න"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ඇඟිලි සලකුණු නිරූපකය"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ඔබව සොයමින්…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"මුහුණ නිරූපකය"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"ගබඩාව"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"ඉඟි"</string>      <string name="instant_apps" msgid="6647570248119804907">"ක්ෂණික යෙදුම්"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"ක්ෂණික යෙදුම් ස්ථාපනය කිරීම අවශ්ය නොවේ."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"ස්ථාපනය නොකර යෙදුම විවෘත කර ඇත."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ස්ථාපනය නොකර යෙදුම විවෘත කර ඇත. තව දැන ගැනීමට තට්ටු කරන්න."</string>      <string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string> -    <string name="go_to_web" msgid="2650669128861626071">"බ්රවුසරය වෙත යන්න"</string> +    <string name="go_to_web" msgid="1106022723459948514">"වෙබය වෙත යන්න"</string>      <string name="mobile_data" msgid="7094582042819250762">"ජංගම දත්ත"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ක්රියා විරහිතයි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 835289605382..233a81b9c52f 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Vyberte nové rozloženie úlohy"</string>      <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblasť správy pomocníka"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdiť"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Klepnite na senzor odtlačkov prstov"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona odtlačku prsta"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hľadáme vás…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona tváre"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth pripojené."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Úložisko"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Tipy"</string>      <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikácie"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikácie nevyžadujú inštaláciu."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikácia <xliff:g id="APP">%1$s</xliff:g> je spustená"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikácia bola otvorená bez inštalácie."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikácia bola otvorená bez inštalácie. Klepnutím zobrazíte ďalšie informácie."</string>      <string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Otvoriť prehliadač"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Prejsť na internet"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilné dáta"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Pripojenie Wi‑Fi je vypnuté"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 2611f7a3d3db..c7e661a9213b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"odpri fotoaparat"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Izberite novo postavitev opravil"</string>      <string name="cancel" msgid="6442560571259935130">"Prekliči"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Območje sporočila pomoči"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potrdite"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotaknite se tipala prstnih odtisov"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona prstnih odtisov"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Preverjanje vašega obraza …"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona obraza"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Povezava Bluetooth vzpostavljena."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Namigi"</string>      <string name="instant_apps" msgid="6647570248119804907">"Nenamestljive aplikacije"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Nenamestljivih aplikacij ni treba namestiti."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se izvaja"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je odprta brez namestitve."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je odprta brez namestitve. Dotaknite se, če želite izvedeti več."</string>      <string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Odpri brskalnik"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Pojdi v splet"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobilni podatki"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je izklopljen"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index e7b32545b644..f4d3d2a27f28 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"hap kamerën"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Zgjidh strukturën e re të detyrës"</string>      <string name="cancel" msgid="6442560571259935130">"Anulo"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zona e mesazhit të ndihmës"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Konfirmo"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Prek sensorin e gjurmës së gishtit"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona e gjurmës së gishtit"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Po të kërkojmë…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona e fytyrës"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butoni i zmadhimit të pajtueshmërisë."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zmadho nga një ekran i vogël në të madh."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Pajisja është lidhur me \"bluetooth\"."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Hapësira ruajtëse"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Sugjerimet"</string>      <string name="instant_apps" msgid="6647570248119804907">"Aplikacionet e çastit"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacionet e çastit nuk kërkojnë instalim."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Po ekzekutohet <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacioni u hap pa u instaluar."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacioni u hap pa u instaluar. Trokit për të mësuar më shumë."</string>      <string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Shko te shfletuesi"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Shko në ueb"</string>      <string name="mobile_data" msgid="7094582042819250762">"Të dhënat celulare"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi është joaktiv"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 323d78b1d2b7..58252315ad64 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -104,16 +104,12 @@      <string name="camera_label" msgid="7261107956054836961">"отвори камеру"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Изабери нови распоред задатака"</string>      <string name="cancel" msgid="6442560571259935130">"Откажи"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област поруке за помоћ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потврди"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Додирните сензор за отисак прста"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона отиска прста"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Тражимо вас…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона лица"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth је прикључен."</string> @@ -835,9 +831,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Меморијски простор"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Савети"</string>      <string name="instant_apps" msgid="6647570248119804907">"Инстант апликације"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликације не захтевају инсталацију."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Апликација се отворила без инсталирања."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Апликација се отворила без инсталирања. Додирните да бисте сазнали више."</string>      <string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Иди на прегледач"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Иди на веб"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобилни подаци"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi је искључен"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 97e0278577c0..7040ec2e30f0 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"öppna kameran"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Välj en ny layout för uppgiften"</string>      <string name="cancel" msgid="6442560571259935130">"Avbryt"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område för hjälpmeddelande"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekräfta"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Tryck på fingeravtryckssensorn"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon för fingeravtryck"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Håller utkik efter dig …"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansiktsikon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ansluten."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Tips"</string>      <string name="instant_apps" msgid="6647570248119804907">"Snabbappar"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Snabbappar behöver inte installeras."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> körs"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Appen öppnades utan installation."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Appen öppnades utan installation. Tryck om du vill veta mer."</string>      <string name="app_info" msgid="6856026610594615344">"Info om appen"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Öppna webbläsaren"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Öppna webbplatsen"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi är inaktiverat"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 1419dcee2507..0633e8ad428f 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Chagua muundo mpya wa kazi"</string>      <string name="cancel" msgid="6442560571259935130">"Ghairi"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Sehemu ya ujumbe wa usaidizi"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Thibitisha"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Gusa kitambua alama ya kidole"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Aikoni ya alama ya kidole"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Inakutafuta…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Aikoni ya uso"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Hifadhi"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Vidokezo"</string>      <string name="instant_apps" msgid="6647570248119804907">"Programu Zinazofunguka Papo Hapo"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Huhitaji kusakinisha programu zinazofunguka papo hapo."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> inaendelea kutumika"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Programu inafunguka bila kusakinishwa."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Programu inafunguka bila kusakinishwa. Gusa ili upate maelezo zaidi."</string>      <string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Tumia kivinjari"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Nenda kwenye wavuti"</string>      <string name="mobile_data" msgid="7094582042819250762">"Data ya simu"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g><xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi imezimwa"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index ba75212f8bdd..469e797c7113 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"புதிய பணி தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>      <string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"உதவிச் செய்திக்கான பகுதி"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"உறுதிப்படுத்துக"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"கைரேகை உணர்வியைத் தொடவும்"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"கைரேகை ஐகான்"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"உங்கள் முகத்தைத் தேடுகிறது…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"முக ஐகான்"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"சேமிப்பிடம்"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"குறிப்புகள்"</string>      <string name="instant_apps" msgid="6647570248119804907">"இன்ஸ்டண்ட் ஆப்ஸ்"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"இன்ஸ்டண்ட் பயன்பாடுகளுக்கு நிறுவல் தேவையில்லை."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string> -    <string name="go_to_web" msgid="2650669128861626071">"உலாவிக்குச் செல்"</string> +    <string name="go_to_web" msgid="1106022723459948514">"இணையத்திற்குச் செல்"</string>      <string name="mobile_data" msgid="7094582042819250762">"மொபைல் டேட்டா"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"வைஃபை முடக்கத்தில் உள்ளது"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 268ad189b8f8..5d869f130a2c 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"కొత్త విధి లేఅవుట్ను ఎంచుకోండి"</string>      <string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"సహాయ సందేశ ప్రాంతం"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"నిర్ధారించు"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"వేలిముద్ర సెన్సార్ను తాకండి"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"వేలిముద్ర చిహ్నం"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"మీ కోసం చూస్తోంది…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ముఖ చిహ్నం"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"నిల్వ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"సూచనలు"</string>      <string name="instant_apps" msgid="6647570248119804907">"తక్షణ యాప్లు"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"తక్షణ అనువర్తనాలకు ఇన్స్టాలేషన్ అవసరం లేదు."</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"యాప్ సమాచారం"</string> -    <string name="go_to_web" msgid="2650669128861626071">"బ్రౌజర్కు వెళ్లండి"</string> +    <string name="go_to_web" msgid="1106022723459948514">"వెబ్కు వెళ్లు"</string>      <string name="mobile_data" msgid="7094582042819250762">"మొబైల్ డేటా"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ఆఫ్లో ఉంది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index dea18e5ea332..408c5a0fe944 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"เปิดกล้อง"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"เลือกรูปแบบงานใหม่"</string>      <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"พื้นที่ข้อความช่วยเหลือ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ยืนยัน"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"แตะเซ็นเซอร์ลายนิ้วมือ"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ไอคอนลายนิ้วมือ"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"กำลังหาใบหน้าคุณ…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ไอคอนใบหน้า"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"เชื่อมต่อบลูทูธแล้ว"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"พื้นที่เก็บข้อมูล"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"คำแนะนำ"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant App"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps ไม่ต้องใช้การติดตั้ง"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ทำงานอยู่"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"เปิดแอปได้โดยไม่ต้องติดตั้ง"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"เปิดแอปได้โดยไม่ต้องติดตั้ง แตะเพื่อดูข้อมูลเพิ่มเติม"</string>      <string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string> -    <string name="go_to_web" msgid="2650669128861626071">"ไปที่เบราว์เซอร์"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ไปที่เว็บ"</string>      <string name="mobile_data" msgid="7094582042819250762">"เน็ตมือถือ"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ปิดอยู่"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 11e07a0bb607..8da4946f1090 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"buksan ang camera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Pumili ng bagong layout ng gawain"</string>      <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Lugar ng mensahe ng tulong"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Kumpirmahin"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Pindutin ang fingerprint sensor"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icon ng fingerprint"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hinahanap ka…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Nakakonekta ang Bluetooth."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Mga Hint"</string>      <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Hindi kailangang i-install ang mga instant na app."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Nabuksan ang app nang hindi ini-install."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Nabuksan ang app nang hindi ini-install. I-tap para matuto pa."</string>      <string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Pumunta sa browser"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Pumunta sa web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Naka-off ang Wi-Fi"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index bda7fefb1f50..de8ed9d02c8a 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni görev düzenini seçin"</string>      <string name="cancel" msgid="6442560571259935130">"İptal"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yardım mesajı alanı"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Onaylayın"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Parmak izi sensörüne dokunun"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Parmak izi simgesi"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Yüzünüz tanınmaya çalışılıyor…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Yüz simgesi"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Depolama alanı"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"İpuçları"</string>      <string name="instant_apps" msgid="6647570248119804907">"Hazır Uygulamalar"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Hazır uygulamaların yüklenmesi gerekmez."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Uygulama yüklenmeden açıldı."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Uygulama yüklenmeden açıldı. Daha fazla bilgi için dokunun."</string>      <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Tarayıcıya git"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Web\'e git"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobil veriler"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Kablosuz bağlantı kapalı"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index ce3572eef7a3..6c2e66171f60 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -105,16 +105,12 @@      <string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Виберіть новий макет завдання"</string>      <string name="cancel" msgid="6442560571259935130">"Скасувати"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Область довідкового повідомлення"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Підтвердити"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Торкніться сканера відбитків пальців"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок відбитка пальця"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Пошук обличчя…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок обличчя"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string> @@ -843,9 +839,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Пам’ять"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Поради"</string>      <string name="instant_apps" msgid="6647570248119804907">"Додатки з миттєвим запуском"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Додатки з миттєвим запуском не потрібно встановлювати."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> працює"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Додаток відкрито без встановлення."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Додаток відкрито без встановлення. Торкніться, щоб дізнатися більше."</string>      <string name="app_info" msgid="6856026610594615344">"Про додаток"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Веб-переглядач"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Перейти на веб-сайт"</string>      <string name="mobile_data" msgid="7094582042819250762">"Мобільний трафік"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi вимкнено"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 50412d298b04..88391b0602d2 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"نئے کام کا لے آؤٹ منتخب کریں"</string>      <string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"امدادی پیغام کا علاقہ"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تصدیق کریں"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"فنگر پرنٹ سینسر پر ٹچ کریں"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"فنگر پرنٹ آئیکن"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"آپ کے لیے تلاش کیا جا رہا ہے…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"چہرے کا آئیکن"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string> @@ -829,9 +825,14 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"اسٹوریج"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"اشارات"</string>      <string name="instant_apps" msgid="6647570248119804907">"فوری ایپس"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"فوری ایپس کو انسٹالیشن کی ضرورت نہیں ہے۔"</string> +    <!-- no translation found for instant_apps_title (8738419517367449783) --> +    <skip /> +    <!-- no translation found for instant_apps_message (1183313016396018086) --> +    <skip /> +    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) --> +    <skip />      <string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string> -    <string name="go_to_web" msgid="2650669128861626071">"براؤزر پر جائیں"</string> +    <string name="go_to_web" msgid="1106022723459948514">"ویب پر جائیں"</string>      <string name="mobile_data" msgid="7094582042819250762">"موبائل ڈیٹا"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi آف ہے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 9446ac1b38d2..37d31c2f20a1 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Yangi vazifa tartibini tanlash"</string>      <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yordam xabari"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"OK"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Barmoq izi skaneriga tegining"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmoq izi belgisi"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Yuzingiz tekshirilmoqda…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Yuz belgisi"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Xotira"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Maslahatlar"</string>      <string name="instant_apps" msgid="6647570248119804907">"Darhol ochiladigan ilovalar"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Darhol ochiladigan ilovalarni o‘rnatish shart emas."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ishlamoqda"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Ilova o‘rnatilmasdan ochildi."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ilova o‘rnatilmasdan ochildi. Batafsil axborot oolish uchun bu yerga bosing."</string>      <string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Brauzerni ochish"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Brauzerga o‘tish"</string>      <string name="mobile_data" msgid="7094582042819250762">"Mobil internet"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi o‘chiq"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index c2045afe24cf..f476790795f8 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"mở máy ảnh"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Chọn bố cục tác vụ mới"</string>      <string name="cancel" msgid="6442560571259935130">"Hủy"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Vùng thông báo trợ giúp"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Xác nhận"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Chạm vào cảm biến vân tay"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Biểu tượng vân tay"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Đang tìm kiếm bạn…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Biểu tượng khuôn mặt"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Đã kết nối bluetooth."</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Bộ nhớ"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Gợi ý"</string>      <string name="instant_apps" msgid="6647570248119804907">"Ứng dụng tức thì"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Ứng dụng tức thì không yêu cầu cài đặt."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> đang chạy"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Ứng dụng được mở mà không cần cài đặt."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ứng dụng được mở mà không cần cài đặt. Nhấn để tìm hiểu thêm."</string>      <string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Đi tới trình duyệt"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Truy cập web"</string>      <string name="mobile_data" msgid="7094582042819250762">"Dữ liệu di động"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi tắt"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index bc13033a49ed..aaa4c6359361 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"打开相机"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"选择新的任务布局"</string>      <string name="cancel" msgid="6442560571259935130">"取消"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"帮助消息区域"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"确认"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"请触摸指纹传感器"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指纹图标"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在查找中…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"面孔图标"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"蓝牙已连接。"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"存储空间"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>      <string name="instant_apps" msgid="6647570248119804907">"免安装应用"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"免安装应用无需安装就能使用。"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"正在运行<xliff:g id="APP">%1$s</xliff:g>"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"已打开免安装应用。"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已打开免安装应用。点按即可了解详情。"</string>      <string name="app_info" msgid="6856026610594615344">"应用信息"</string> -    <string name="go_to_web" msgid="2650669128861626071">"转到浏览器"</string> +    <string name="go_to_web" msgid="1106022723459948514">"转到网页版"</string>      <string name="mobile_data" msgid="7094582042819250762">"移动数据"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"WLAN 已关闭"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index ff045b191dfa..aad4b4fe6edb 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"開啟相機"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"選取新的工作版面配置"</string>      <string name="cancel" msgid="6442560571259935130">"取消"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"說明訊息區域"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"請輕觸指紋感應器"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋圖示"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在搜尋您的臉孔…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"面孔圖示"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string> @@ -831,9 +827,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>      <string name="instant_apps" msgid="6647570248119804907">"即時應用程式"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"即時應用程式無需安裝即可使用。"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> 運作中"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"已開啟免安裝應用程式。"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已開啟免安裝應用程式。輕按即可瞭解詳情。"</string>      <string name="app_info" msgid="6856026610594615344">"應用程式資料"</string> -    <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string> +    <string name="go_to_web" msgid="1106022723459948514">"前往網頁版"</string>      <string name="mobile_data" msgid="7094582042819250762">"流動數據"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi 已關閉"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 143bf914d60b..6b885455766c 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"選取新工作版面配置"</string>      <string name="cancel" msgid="6442560571259935130">"取消"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"說明訊息區域"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"請輕觸指紋感應器"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋圖示"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在尋找你的臉孔…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"臉孔圖示"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>      <string name="instant_apps" msgid="6647570248119804907">"免安裝應用程式"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"免安裝應用程式不必安裝就能使用。"</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"正在執行「<xliff:g id="APP">%1$s</xliff:g>」"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"已開啟免安裝應用程式。"</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已開啟免安裝應用程式。輕觸即可瞭解詳情。"</string>      <string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string> -    <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string> +    <string name="go_to_web" msgid="1106022723459948514">"前往網頁版"</string>      <string name="mobile_data" msgid="7094582042819250762">"行動數據"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi 已關閉"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 89030b70c3aa..085c3b330a6b 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -103,16 +103,12 @@      <string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>      <string name="recents_caption_resize" msgid="3517056471774958200">"Khetha isakhiwo somsebenzi omusha"</string>      <string name="cancel" msgid="6442560571259935130">"Khansela"</string> -    <!-- no translation found for accessibility_biometric_dialog_help_area (8953787076940186847) --> -    <skip /> -    <!-- no translation found for biometric_dialog_confirm (6468457350041712674) --> -    <skip /> +    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Indawo yosizo lomlayezo"</string> +    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Qinisekisa"</string>      <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Thinta inzwa yesigxivizo somunwe"</string>      <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Isithonjana sezigxivizo zeminwe"</string> -    <!-- no translation found for face_dialog_looking_for_face (7049276266074494689) --> -    <skip /> -    <!-- no translation found for accessibility_face_dialog_face_icon (2658119009870383490) --> -    <skip /> +    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Kufunwa wena…"</string> +    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Isithonjana sobuso"</string>      <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>      <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>      <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string> @@ -829,9 +825,11 @@      <string name="notification_channel_storage" msgid="3077205683020695313">"Isitoreji"</string>      <string name="notification_channel_hints" msgid="7323870212489152689">"Ukubonisa"</string>      <string name="instant_apps" msgid="6647570248119804907">"Izinhlelo zokusebenza ezisheshayo"</string> -    <string name="instant_apps_message" msgid="8116608994995104836">"Izinhlelo zokusebenza ezisheshayo azidingi ukufakwa."</string> +    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> esebenzayo"</string> +    <string name="instant_apps_message" msgid="1183313016396018086">"Uhlelo lokusebenza luvulwe ngaphndle kokufakwa."</string> +    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Uhlelo lokusebenza luvulwe ngaphandle kokufakwa. Thepha ukuze ufunde kabanzi."</string>      <string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string> -    <string name="go_to_web" msgid="2650669128861626071">"Iya kusiphequluli"</string> +    <string name="go_to_web" msgid="1106022723459948514">"Iya kuwebhu"</string>      <string name="mobile_data" msgid="7094582042819250762">"Idatha yeselula"</string>      <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="wifi_is_off" msgid="1838559392210456893">"I-Wi-Fi ivaliwe"</string> diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 710b5f724add..defc49b5fac1 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -20,6 +20,10 @@ android_library {          "src/**/I*.aidl",      ], +    static_libs: [ +        "SystemUIPluginLib" +    ], +      // Enforce that the library is build agains java 7 so that there are      // no compatibility issues with launcher      java_version: "1.7", diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java new file mode 100644 index 000000000000..985789415363 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.shared.plugins; + +import android.content.Context; +import android.os.Looper; + +/** + * Provides necessary components for initializing {@link PluginManagerImpl}. + */ +public interface PluginInitializer { + +    Looper getBgLooper(); + +    /** +     * This Runnable is run on the bg looper during initialization of {@link PluginManagerImpl}. +     * It can be null. +     */ +    Runnable getBgInitCallback(); + +    String[] getWhitelistedPlugins(Context context); +} diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java index 7bc7e5f0095e..e80c079f60de 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java @@ -12,7 +12,7 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import android.app.Notification;  import android.app.Notification.Action; @@ -39,12 +39,14 @@ import android.view.LayoutInflater;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; -import com.android.systemui.plugins.VersionInfo.InvalidVersionException; +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginFragment; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.List; -import com.android.systemui.R;  public class PluginInstanceManager<T extends Plugin> { @@ -71,8 +73,7 @@ public class PluginInstanceManager<T extends Plugin> {      PluginInstanceManager(Context context, String action, PluginListener<T> listener,              boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {          this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version, -                manager, Build.IS_DEBUGGABLE, -                context.getResources().getStringArray(R.array.config_pluginWhitelist)); +                manager, Build.IS_DEBUGGABLE, manager.getWhitelistedPlugins());      }      @VisibleForTesting @@ -114,7 +115,7 @@ public class PluginInstanceManager<T extends Plugin> {      public void destroy() {          if (DEBUG) Log.d(TAG, "stopListening"); -        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); +        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);          for (PluginInfo plugin : plugins) {              mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,                      plugin.mPlugin).sendToTarget(); @@ -132,7 +133,7 @@ public class PluginInstanceManager<T extends Plugin> {      public boolean checkAndDisable(String className) {          boolean disableAny = false; -        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); +        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);          for (PluginInfo info : plugins) {              if (className.startsWith(info.mPackage)) {                  disable(info); @@ -143,7 +144,7 @@ public class PluginInstanceManager<T extends Plugin> {      }      public boolean disableAll() { -        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); +        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);          for (int i = 0; i < plugins.size(); i++) {              disable(plugins.get(i));          } @@ -165,7 +166,7 @@ public class PluginInstanceManager<T extends Plugin> {      }      public <T> boolean dependsOn(Plugin p, Class<T> cls) { -        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); +        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);          for (PluginInfo info : plugins) {              if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) {                  return info.mVersion != null && info.mVersion.hasClass(cls); diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java index 298eaf18dce5..208f4fedfe27 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java @@ -12,10 +12,12 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import android.text.TextUtils; +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginListener;  import com.android.systemui.plugins.annotations.ProvidesInterface;  public interface PluginManager { @@ -40,14 +42,17 @@ public interface PluginManager {      <T> boolean dependsOn(Plugin p, Class<T> cls); -    static <P> String getAction(Class<P> cls) { -        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); -        if (info == null) { -            throw new RuntimeException(cls + " doesn't provide an interface"); +    class Helper { +        public static <P> String getAction(Class<P> cls) { +            ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); +            if (info == null) { +                throw new RuntimeException(cls + " doesn't provide an interface"); +            } +            if (TextUtils.isEmpty(info.action())) { +                throw new RuntimeException(cls + " doesn't provide an action"); +            } +            return info.action();          } -        if (TextUtils.isEmpty(info.action())) { -            throw new RuntimeException(cls + " doesn't provide an action"); -        } -        return info.action();      } +  } diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java index 1cbf1fe0f2c4..7f1d161123f2 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java @@ -12,7 +12,7 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import android.app.Notification;  import android.app.Notification.Action; @@ -41,10 +41,11 @@ import android.widget.Toast;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper; -import com.android.systemui.plugins.PluginInstanceManager.PluginInfo; + +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper; +import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;  import com.android.systemui.plugins.annotations.ProvidesInterface;  import dalvik.system.PathClassLoader; @@ -79,31 +80,33 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage      private Looper mLooper;      private boolean mWtfsSet; -    public PluginManagerImpl(Context context) { +    public PluginManagerImpl(Context context, PluginInitializer initializer) {          this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE, -                context.getResources().getStringArray(R.array.config_pluginWhitelist), -                Thread.getUncaughtExceptionPreHandler()); +                Thread.getUncaughtExceptionPreHandler(), initializer);      }      @VisibleForTesting      PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable, -            String[] whitelistedPlugins, UncaughtExceptionHandler defaultHandler) { +            UncaughtExceptionHandler defaultHandler, PluginInitializer initializer) {          mContext = context;          mFactory = factory; -        mLooper = Dependency.get(Dependency.BG_LOOPER); +        mLooper = initializer.getBgLooper();          isDebuggable = debuggable; -        mWhitelistedPlugins.addAll(Arrays.asList(whitelistedPlugins)); +        mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));          mPluginPrefs = new PluginPrefs(mContext);          PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(                  defaultHandler);          Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler); -        new Handler(mLooper).post(() -> { -            // Plugin dependencies that don't have another good home can go here, but -            // dependencies that have better places to init can happen elsewhere. -            Dependency.get(PluginDependencyProvider.class) -                    .allowPluginDependency(ActivityStarter.class); -        }); + +        Runnable bgRunnable = initializer.getBgInitCallback(); +        if (bgRunnable != null) { +            new Handler(mLooper).post(bgRunnable); +        } +    } + +    public String[] getWhitelistedPlugins() { +        return mWhitelistedPlugins.toArray(new String[0]);      }      public <T extends Plugin> T getOneShotPlugin(Class<T> cls) { @@ -121,7 +124,9 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage          if (Looper.myLooper() != Looper.getMainLooper()) {              throw new RuntimeException("Must be called from UI thread");          } -        PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null, +        // Passing null causes compiler to complain about incompatible (generic) types. +        PluginListener<Plugin> dummy = null; +        PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, dummy,                  false, mLooper, cls, this);          mPluginPrefs.addAction(action);          PluginInfo<T> info = p.getPlugin(); @@ -140,7 +145,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage      public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,              boolean allowMultiple) { -        addPluginListener(PluginManager.getAction(cls), listener, cls, allowMultiple); +        addPluginListener(PluginManager.Helper.getAction(cls), listener, cls, allowMultiple);      }      public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener, @@ -293,8 +298,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage      public void handleWtfs() {          if (!mWtfsSet) {              mWtfsSet = true; -            Log.setWtfHandler((tag, what, system) -> { -                throw new CrashWhilePluginActiveException(what); +            Log.setWtfHandler(new Log.TerribleFailureHandler() { +                @Override +                public void onTerribleFailure(String tag, Log.TerribleFailure what, +                        boolean system) { +                    throw new CrashWhilePluginActiveException(what); +                }              });          }      } diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginPrefs.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java index 3671b3c1689f..c0c5d7051cea 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginPrefs.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java @@ -12,7 +12,7 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import android.content.Context;  import android.content.SharedPreferences; diff --git a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/VersionInfo.java index facfd982408a..bb845cd87923 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/VersionInfo.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/VersionInfo.java @@ -12,7 +12,9 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins; + +import android.util.ArrayMap;  import com.android.systemui.plugins.annotations.Dependencies;  import com.android.systemui.plugins.annotations.DependsOn; @@ -20,7 +22,7 @@ import com.android.systemui.plugins.annotations.ProvidesInterface;  import com.android.systemui.plugins.annotations.Requirements;  import com.android.systemui.plugins.annotations.Requires; -import android.util.ArrayMap; +import java.util.function.BiConsumer;  public class VersionInfo { @@ -73,25 +75,32 @@ public class VersionInfo {      }      public void checkVersion(VersionInfo plugin) throws InvalidVersionException { -        ArrayMap<Class<?>, Version> versions = new ArrayMap<>(mVersions); -        plugin.mVersions.forEach((aClass, version) -> { -            Version v = versions.remove(aClass); -            if (v == null) { -                v = createVersion(aClass); -            } -            if (v == null) { -                throw new InvalidVersionException(aClass.getSimpleName() -                        + " does not provide an interface", false); -            } -            if (v.mVersion != version.mVersion) { -                throw new InvalidVersionException(aClass, v.mVersion < version.mVersion, v.mVersion, -                        version.mVersion); +        final ArrayMap<Class<?>, Version> versions = new ArrayMap<>(mVersions); +        plugin.mVersions.forEach(new BiConsumer<Class<?>, Version>() { +            @Override +            public void accept(Class<?> aClass, Version version) { +                Version v = versions.remove(aClass); +                if (v == null) { +                    v = VersionInfo.this.createVersion(aClass); +                } +                if (v == null) { +                    throw new InvalidVersionException(aClass.getSimpleName() +                            + " does not provide an interface", false); +                } +                if (v.mVersion != version.mVersion) { +                    throw new InvalidVersionException(aClass, v.mVersion < version.mVersion, +                            v.mVersion, +                            version.mVersion); +                }              }          }); -        versions.forEach((aClass, version) -> { -            if (version.mRequired) { -                throw new InvalidVersionException("Missing required dependency " -                        + aClass.getSimpleName(), false); +        versions.forEach(new BiConsumer<Class<?>, Version>() { +            @Override +            public void accept(Class<?> aClass, Version version) { +                if (version.mRequired) { +                    throw new InvalidVersionException("Missing required dependency " +                            + aClass.getSimpleName(), false); +                }              }          });      } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index b04d04717be5..c7910f97675e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -342,6 +342,20 @@ public class ActivityManagerWrapper {      }      /** +     * Moves an already resumed task to the side of the screen to initiate split screen. +     */ +    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, +            Rect initialBounds) { +        try { +            return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId, +                    createMode, true /* onTop */, false /* animate */, initialBounds, +                    true /* showRecents */); +        } catch (RemoteException e) { +            return false; +        } +    } + +    /**       * Registers a task stack listener with the system.       * This should be called on the main thread.       */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java index 36fb3a7b4307..7154f5396fbd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -21,6 +21,8 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE  import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;  import android.app.ActivityOptions; +import android.content.Context; +import android.os.Handler;  /**   * Wrapper around internal ActivityOptions creation. @@ -43,4 +45,17 @@ public abstract class ActivityOptionsCompat {              RemoteAnimationAdapterCompat remoteAnimationAdapter) {          return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());      } + +    public static ActivityOptions makeCustomAnimation(Context context, int enterResId, +            int exitResId, final Runnable callback, final Handler callbackHandler) { +        return ActivityOptions.makeCustomAnimation(context, enterResId, exitResId, callbackHandler, +                new ActivityOptions.OnAnimationStartedListener() { +                    @Override +                    public void onAnimationStarted() { +                        if (callback != null) { +                            callbackHandler.post(callback); +                        } +                    } +                }); +    }  } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index d83b36d6ea80..3191d14c5a83 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -151,6 +151,25 @@ public class WindowManagerWrapper {          }      } +    public void setPipVisibility(final boolean visible) { +        try { +            WindowManagerGlobal.getWindowManagerService().setPipVisibility(visible); +        } catch (RemoteException e) { +            Log.e(TAG, "Unable to reach window manager", e); +        } +    } + +    /** +     * @return whether there is a soft nav bar. +     */ +    public boolean hasSoftNavigationBar() { +        try { +            return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(); +        } catch (RemoteException e) { +            return false; +        } +    } +      /**       * @return The side of the screen where navigation bar is positioned.       * @see #NAV_BAR_POS_RIGHT diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 5bbbc52f4cbc..28eff46db1d0 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -14,7 +14,7 @@ import androidx.annotation.VisibleForTesting;  import com.android.systemui.Dependency;  import com.android.systemui.plugins.ClockPlugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  /**   * Switch to show plugin clock when plugin is connected, otherwise it will show default clock. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index b159b393862a..b8df3c067969 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -342,12 +342,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe                  case SimPuk:                      // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home                      SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); -                    if (securityMode != SecurityMode.None -                            || !mLockPatternUtils.isLockScreenDisabled( +                    if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(                              KeyguardUpdateMonitor.getCurrentUser())) { -                        showSecurityScreen(securityMode); -                    } else {                          finish = true; +                    } else { +                        showSecurityScreen(securityMode);                      }                      break; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 10c8ec09bd5b..f1b53fec0714 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -86,9 +86,8 @@ import com.android.internal.telephony.TelephonyIntents;  import com.android.internal.util.Preconditions;  import com.android.internal.widget.LockPatternUtils;  import com.android.settingslib.WirelessUtils; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.system.ActivityManagerWrapper; - +import com.android.systemui.shared.system.TaskStackChangeListener;  import com.google.android.collect.Lists;  import java.io.FileDescriptor; @@ -2218,8 +2217,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {          }      } -    private final SysUiTaskStackChangeListener -            mTaskStackListener = new SysUiTaskStackChangeListener() { +    private final TaskStackChangeListener +            mTaskStackListener = new TaskStackChangeListener() {          @Override          public void onTaskStackChangedBackground() {              try { diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index b2cf305d0533..fe1fe1aba908 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -39,9 +39,10 @@ import com.android.systemui.fragments.FragmentService;  import com.android.systemui.keyguard.ScreenLifecycle;  import com.android.systemui.keyguard.WakefulnessLifecycle;  import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.PluginInitializerImpl;  import com.android.systemui.plugins.PluginDependencyProvider; -import com.android.systemui.plugins.PluginManager; -import com.android.systemui.plugins.PluginManagerImpl; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManagerImpl;  import com.android.systemui.plugins.VolumeDialogController;  import com.android.systemui.power.EnhancedEstimates;  import com.android.systemui.power.EnhancedEstimatesImpl; @@ -236,7 +237,7 @@ public class Dependency extends SystemUI {                  new DeviceProvisionedControllerImpl(mContext));          mProviders.put(PluginManager.class, () -> -                new PluginManagerImpl(mContext)); +                new PluginManagerImpl(mContext, new PluginInitializerImpl()));          mProviders.put(AssistManager.class, () ->                  new AssistManager(getDependency(DeviceProvisionedController.class), mContext)); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 408e599bc289..77f4bf529f21 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -256,6 +256,12 @@ public class ImageWallpaper extends WallpaperService {                  Log.d(TAG, "onSurfaceRedrawNeeded");              }              super.onSurfaceRedrawNeeded(holder); +            // At the end of this method we should have drawn into the surface. +            // This means that the bitmap should be loaded synchronously if +            // it was already unloaded. +            if (mBackground == null) { +                updateBitmap(mWallpaperManager.getBitmap(true /* hardware */)); +            }              mSurfaceRedrawNeeded = true;              drawFrame();          } diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index bd2b7a577b3d..1af2156c4bbe 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -16,6 +16,11 @@  package com.android.systemui; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; +import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; +import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; +  import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.Context; @@ -33,11 +38,7 @@ import android.os.UserHandle;  import android.provider.Settings;  import android.util.Log;  import android.view.MotionEvent; -  import com.android.systemui.OverviewProxyService.OverviewProxyListener; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.recents.IOverviewProxy;  import com.android.systemui.shared.recents.ISystemUiProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -46,17 +47,11 @@ import com.android.systemui.statusbar.phone.StatusBar;  import com.android.systemui.statusbar.policy.CallbackController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; -  import java.io.FileDescriptor;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.List; -import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; -import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; -  /**   * Class to send information from overview to launcher with a binder.   */ @@ -133,7 +128,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis              }              long token = Binder.clearCallingIdentity();              try { -                EventBus.getDefault().post(new DockedFirstAnimationFrameEvent()); +                Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class); +                if (divider != null) { +                    divider.onDockedFirstAnimationFrame(); +                }              } finally {                  Binder.restoreCallingIdentity(token);              } @@ -314,8 +312,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis                  getDefaultInteractionFlags());          // Listen for the package update changes. -        if (SystemServicesProxy.getInstance(context) -                .isSystemUser(mDeviceProvisionedController.getCurrentUser())) { +        if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {              updateEnabledState();              mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);              IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java index ddd48330e679..f6ad62616a96 100644 --- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java +++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java @@ -21,7 +21,7 @@ import android.util.Log;  import android.view.View;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.plugins.ViewProvider;  /** diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index f9dbf4a15e5c..fb343f9b9b45 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -22,27 +22,10 @@ import android.view.View;  public interface RecentsComponent {      void showRecentApps(boolean triggeredFromAltTab); -    void showNextAffiliatedTask(); -    void showPrevAffiliatedTask();      /**       * Docks the top-most task and opens recents.       */ -    boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds, +    boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,              int metricsDockAction); - -    /** -     * Called during a drag-from-navbar-in gesture. -     * -     * @param distanceFromTop the distance of the current drag in gesture from the top of the -     *                        screen -     */ -    void onDraggingInRecents(float distanceFromTop); - -    /** -     * Called when the gesture to drag in recents ended. -     * -     * @param velocity the velocity of the finger when releasing it in pixels per second -     */ -    void onDraggingInRecentsEnded(float velocity);  } diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index a3b539588d9b..0215fda81485 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -61,13 +61,14 @@ public class SwipeHelper implements Gefingerpoken {      public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;      static final float MAX_SCROLL_SIZE_FRACTION = 0.3f; +    protected final Handler mHandler; +      private float mMinSwipeProgress = 0f;      private float mMaxSwipeProgress = 1f;      private final FlingAnimationUtils mFlingAnimationUtils;      private float mPagingTouchSlop;      private final Callback mCallback; -    private final Handler mHandler;      private final int mSwipeDirection;      private final VelocityTracker mVelocityTracker;      private final FalsingManager mFalsingManager; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index b96a6049421b..78053b28c4c3 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -34,7 +34,7 @@ import android.util.TimingsTraceLog;  import com.android.systemui.plugins.OverlayPlugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.statusbar.phone.StatusBar;  import com.android.systemui.statusbar.phone.StatusBarWindowController;  import com.android.systemui.util.NotificationChannels; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java index bb82a54c12f1..8e29841e887d 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java @@ -28,8 +28,8 @@ import java.io.FileDescriptor;  import java.io.PrintWriter;  import com.android.internal.os.BinderInternal; -import com.android.systemui.plugins.PluginManager; -import com.android.systemui.plugins.PluginManagerImpl; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManagerImpl;  public class SystemUIService extends Service { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index e6026c14cd28..21b21d9f5527 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -44,7 +44,7 @@ public class DozeLog {      public static final int PULSE_REASON_SENSOR_PICKUP = 3;      public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;      public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; -    public static final int PULSE_REASON_SENSOR_REACH = 6; +    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 6;      public static final int REASON_SENSOR_WAKE_UP = 7;      private static boolean sRegisterKeyguardCallback = true; @@ -177,9 +177,9 @@ public class DozeLog {          log("state " + state);      } -    public static void traceReachWakeUp() { +    public static void traceWakeLockScreenWakeUp() {          if (!ENABLED) return; -        log("reachWakeUp"); +        log("wakeLockScreenWakeUp");      }      public static void traceProximityResult(Context context, boolean near, long millis, @@ -199,7 +199,7 @@ public class DozeLog {              case PULSE_REASON_SENSOR_PICKUP: return "pickup";              case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";              case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; -            case PULSE_REASON_SENSOR_REACH: return "reach"; +            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakeLockScreen";              case REASON_SENSOR_WAKE_UP: return "wakeup";              default: throw new IllegalArgumentException("bad reason: " + pulseReason);          } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index f9dfb5d10403..701394763fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -113,10 +113,10 @@ public class DozeSensors {                          true /* reports touch coordinates */,                          true /* touchscreen */),                  new TriggerSensor( -                        findSensorWithType(config.reachSensorType()), -                        Settings.Secure.DOZE_REACH_GESTURE, +                        findSensorWithType(config.wakeLockScreenSensorType()), +                        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,                          true /* configured */, -                        DozeLog.PULSE_REASON_SENSOR_REACH, +                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,                          false /* reports touch coordinates */,                          false /* touchscreen */),                  new WakeScreenSensor(), diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 73393047cc45..c61e10aa77ab 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -26,7 +26,7 @@ import com.android.systemui.Dependency;  import com.android.systemui.plugins.DozeServicePlugin;  import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import java.io.FileDescriptor;  import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 31548b93ea60..cb91d7815be5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -128,7 +128,7 @@ public class DozeTriggers implements DozeMachine.Part {          boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;          boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;          boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; -        boolean isReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_REACH; +        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;          if (isLongPress) {              requestPulse(pulseReason, sensorPerformedProxCheck); @@ -141,7 +141,7 @@ public class DozeTriggers implements DozeMachine.Part {                  if (isDoubleTap) {                      mDozeHost.onDoubleTap(screenX, screenY);                      mMachine.wakeUp(); -                } else if (isPickup || isReach) { +                } else if (isPickup || isWakeLockScreen) {                      mMachine.wakeUp();                  } else {                      mDozeHost.extendPulse(); @@ -156,8 +156,8 @@ public class DozeTriggers implements DozeMachine.Part {              final boolean withinVibrationThreshold =                      timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();              DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold); -        } else if (isReach) { -            DozeLog.traceReachWakeUp(); +        } else if (isWakeLockScreen) { +            DozeLog.traceWakeLockScreenWakeUp();          }      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java index 745f312a29b4..d833c16c04b3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java @@ -19,9 +19,6 @@ package com.android.systemui.keyguard;  import com.android.internal.policy.IKeyguardDismissCallback;  import com.android.systemui.Dependency;  import com.android.systemui.UiOffloadThread; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; -  import java.util.ArrayList;  /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java index 0cedf9825990..74f770679cc9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java @@ -19,7 +19,6 @@ package com.android.systemui.keyguard;  import android.app.ActivityManager;  import android.app.ActivityOptions;  import android.app.ActivityTaskManager; -import android.app.IActivityManager;  import android.app.IActivityTaskManager;  import android.app.KeyguardManager;  import android.content.ComponentName; @@ -29,11 +28,9 @@ import android.os.Bundle;  import android.os.RemoteException;  import android.os.UserHandle;  import android.util.Log; -  import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener;  public class WorkLockActivityController {      private static final String TAG = WorkLockActivityController.class.getSimpleName(); @@ -111,7 +108,7 @@ public class WorkLockActivityController {          }      } -    private final SysUiTaskStackChangeListener mLockListener = new SysUiTaskStackChangeListener() { +    private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {          @Override          public void onTaskProfileLocked(int taskId, int userId) {              startWorkChallengeInTask(taskId, userId); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java index b7164cbb3271..864a6f9185fa 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java @@ -21,11 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;  import android.content.pm.PackageManager;  import android.content.res.Configuration; - +import android.os.UserHandle; +import android.os.UserManager;  import com.android.systemui.SystemUI; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.component.ExpandPipEvent;  import com.android.systemui.statusbar.CommandQueue; -  import java.io.FileDescriptor;  import java.io.PrintWriter; @@ -47,8 +48,8 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks {          }          // Ensure that we are the primary user's SystemUI. -        final int processUser = SystemServicesProxy.getInstance(mContext).getProcessUser(); -        if (!SystemServicesProxy.getInstance(mContext).isSystemUser(processUser)) { +        final int processUser = UserManager.get(mContext).getUserHandle(); +        if (processUser != UserHandle.USER_SYSTEM) {              throw new IllegalStateException("Non-primary Pip component not currently supported.");          } @@ -58,6 +59,7 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks {          mPipManager.initialize(mContext);          getComponent(CommandQueue.class).addCallbacks(this); +        putComponent(PipUI.class, this);      }      @Override @@ -65,6 +67,10 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks {          mPipManager.showPictureInPictureMenu();      } +    public void expandPip() { +        EventBus.getDefault().send(new ExpandPipEvent()); +    } +      @Override      protected void onConfigurationChanged(Configuration newConfig) {          super.onConfigurationChanged(newConfig); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java index 784ac4e16838..9bf46bb488f3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package com.android.systemui.recents.misc; +package com.android.systemui.pip.phone;  import android.os.Handler;  import android.os.HandlerThread; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java index 5547e2d3985d..9ce2606a2a15 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java @@ -19,21 +19,17 @@ package com.android.systemui.pip.phone;  import android.content.Context;  import android.graphics.PixelFormat;  import android.graphics.Point; -import android.graphics.PointF;  import android.graphics.Rect;  import android.graphics.drawable.Drawable;  import android.view.Gravity;  import android.view.LayoutInflater;  import android.view.View; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup;  import android.view.WindowManager;  import android.view.WindowManager.LayoutParams;  import android.widget.FrameLayout; -  import com.android.systemui.Interpolators;  import com.android.systemui.R; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.WindowManagerWrapper;  public class PipDismissViewController { @@ -59,7 +55,7 @@ public class PipDismissViewController {          if (mDismissView == null) {              // Determine sizes for the view              final Rect stableInsets = new Rect(); -            SystemServicesProxy.getInstance(mContext).getStableInsets(stableInsets); +            WindowManagerWrapper.getInstance().getStableInsets(stableInsets);              final Point windowSize = new Point();              mWindowManager.getDefaultDisplay().getRealSize(windowSize);              final int gradientHeight = mContext.getResources().getDimensionPixelSize( diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index ee15655d87b2..04746c16585a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -17,7 +17,6 @@  package com.android.systemui.pip.phone;  import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.INPUT_CONSUMER_PIP;  import android.app.ActivityManager;  import android.app.ActivityTaskManager; @@ -36,15 +35,15 @@ import android.view.IPinnedStackController;  import android.view.IPinnedStackListener;  import android.view.IWindowManager;  import android.view.WindowManagerGlobal; - +import com.android.systemui.Dependency; +import com.android.systemui.UiOffloadThread;  import com.android.systemui.pip.BasePipManager;  import com.android.systemui.recents.events.EventBus;  import com.android.systemui.recents.events.component.ExpandPipEvent; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper;  import com.android.systemui.shared.system.InputConsumerController; - +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.WindowManagerWrapper;  import java.io.PrintWriter;  /** @@ -72,7 +71,7 @@ public class PipManager implements BasePipManager {      /**       * Handler for system task stack changes.       */ -    SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() { +    TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {          @Override          public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {              mTouchHandler.onActivityPinned(); @@ -80,7 +79,9 @@ public class PipManager implements BasePipManager {              mMenuController.onActivityPinned();              mAppOpsListener.onActivityPinned(packageName); -            SystemServicesProxy.getInstance(mContext).setPipVisibility(true); +            Dependency.get(UiOffloadThread.class).submit(() -> { +                WindowManagerWrapper.getInstance().setPipVisibility(true); +            });          }          @Override @@ -93,7 +94,9 @@ public class PipManager implements BasePipManager {              mTouchHandler.onActivityUnpinned(topActivity);              mAppOpsListener.onActivityUnpinned(); -            SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null); +            Dependency.get(UiOffloadThread.class).submit(() -> { +                WindowManagerWrapper.getInstance().setPipVisibility(topActivity != null); +            });          }          @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index f0ab046f7dbe..ce7da79de794 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -30,7 +30,6 @@ import android.animation.RectEvaluator;  import android.animation.ValueAnimator;  import android.animation.ValueAnimator.AnimatorUpdateListener;  import android.app.ActivityManager.StackInfo; -import android.app.ActivityTaskManager;  import android.app.IActivityManager;  import android.app.IActivityTaskManager;  import android.content.Context; @@ -43,14 +42,11 @@ import android.os.Message;  import android.os.RemoteException;  import android.util.Log;  import android.view.animation.Interpolator; -  import com.android.internal.graphics.SfVsyncFrameCallbackProvider;  import com.android.internal.os.SomeArgs;  import com.android.internal.policy.PipSnapAlgorithm; -import com.android.systemui.recents.misc.ForegroundThread; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.WindowManagerWrapper;  import com.android.systemui.statusbar.FlingAnimationUtils; -  import java.io.PrintWriter;  /** @@ -116,7 +112,7 @@ public class PipMotionHelper implements Handler.Callback {       */      void onConfigurationChanged() {          mSnapAlgorithm.onConfigurationChanged(); -        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); +        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);      }      /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 020c5500c0a0..43e9db7f0ee5 100755 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -16,6 +16,11 @@  package com.android.systemui.pip.tv; +import static android.app.ActivityTaskManager.INVALID_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.view.Display.DEFAULT_DISPLAY; +  import android.app.ActivityManager;  import android.app.ActivityManager.RunningTaskInfo;  import android.app.ActivityManager.StackInfo; @@ -44,22 +49,17 @@ import android.view.IPinnedStackController;  import android.view.IPinnedStackListener;  import android.view.IWindowManager;  import android.view.WindowManagerGlobal; - +import com.android.systemui.Dependency;  import com.android.systemui.R; +import com.android.systemui.UiOffloadThread;  import com.android.systemui.pip.BasePipManager; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper; - +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.WindowManagerWrapper;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.List; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.view.Display.DEFAULT_DISPLAY; -  /**   * Manages the picture-in-picture (PIP) UI and states.   */ @@ -630,7 +630,7 @@ public class PipManager implements BasePipManager {          return false;      } -    private SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() { +    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {          @Override          public void onTaskStackChanged() {              if (DEBUG) Log.d(TAG, "onTaskStackChanged()"); @@ -754,7 +754,9 @@ public class PipManager implements BasePipManager {      }      private void updatePipVisibility(final boolean visible) { -        SystemServicesProxy.getInstance(mContext).setPipVisibility(visible); +        Dependency.get(UiOffloadThread.class).submit(() -> { +            WindowManagerWrapper.getInstance().setPipVisibility(visible); +        });      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java index c58d889270e2..03daa95567ee 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java @@ -18,6 +18,7 @@ import android.util.ArrayMap;  import com.android.systemui.Dependency;  import com.android.systemui.plugins.PluginDependency.DependencyProvider; +import com.android.systemui.shared.plugins.PluginManager;  public class PluginDependencyProvider extends DependencyProvider { diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java new file mode 100644 index 000000000000..108c2d05d76c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.content.Context; +import android.os.Looper; + +import com.android.systemui.Dependency; +import com.android.systemui.shared.plugins.PluginInitializer; +import com.android.systemui.R; + +public class PluginInitializerImpl implements PluginInitializer { +    @Override +    public Looper getBgLooper() { +        return Dependency.get(Dependency.BG_LOOPER); +    } + +    @Override +    public Runnable getBgInitCallback() { +        return new Runnable() { +            @Override +            public void run() { +                // Plugin dependencies that don't have another good home can go here, but +                // dependencies that have better places to init can happen elsewhere. +                Dependency.get(PluginDependencyProvider.class) +                        .allowPluginDependency(ActivityStarter.class); +            } +        }; +    } + +    @Override +    public String[] getWhitelistedPlugins(Context context) { +        return context.getResources().getStringArray(R.array.config_pluginWhitelist); +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index fcd479ce6627..4b5ab2a640ff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -6,9 +6,7 @@ import android.animation.AnimatorSet;  import android.animation.ObjectAnimator;  import android.animation.PropertyValuesHolder;  import android.content.Context; - -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; +import android.content.res.Resources;  import android.util.AttributeSet;  import android.util.Log;  import android.view.LayoutInflater; @@ -18,6 +16,9 @@ import android.view.animation.Interpolator;  import android.view.animation.OvershootInterpolator;  import android.widget.Scroller; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +  import com.android.systemui.R;  import com.android.systemui.qs.QSPanel.QSTileLayout;  import com.android.systemui.qs.QSPanel.TileRecord; @@ -224,7 +225,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {      public boolean updateResources() {          // Update bottom padding, useful for removing extra space once the panel page indicator is          // hidden. -        setPadding(0, 0, 0, +        Resources res = getContext().getResources(); +        final int sidePadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings); +        setPadding(sidePadding, 0, sidePadding,                  getContext().getResources().getDimensionPixelSize(                          R.dimen.qs_paged_tile_layout_padding_bottom));          boolean changed = false; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index c36cdf6ac262..79e508611750 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -256,7 +256,7 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {      public void setExpanded(boolean expanded) {          if (DEBUG) Log.d(TAG, "setExpanded " + expanded);          mQsExpanded = expanded; -        mQSPanel.setListening(mListening && mQsExpanded); +        mQSPanel.setListening(mListening, mQsExpanded);          updateQsState();      } @@ -287,8 +287,7 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {          mListening = listening;          mHeader.setListening(listening);          mFooter.setListening(listening); -        mQSPanel.setListening(mListening && mQsExpanded); -        mQSPanel.getFooter().setListening(listening); +        mQSPanel.setListening(mListening, mQsExpanded);      }      @Override @@ -365,7 +364,11 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {                  .setListener(new AnimatorListenerAdapter() {                      @Override                      public void onAnimationEnd(Animator animation) { -                        getView().animate().setListener(null); +                        if (getView() != null) { +                            // The view could be destroyed before the animation completes when +                            // switching users. +                            getView().animate().setListener(null); +                        }                          mHeaderAnimating = false;                          updateQsState();                      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 7a57fdde6712..e98ef4c09667 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -199,7 +199,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne      public void openDetails(String subPanel) {          QSTile tile = getTile(subPanel); -        showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0}); +        // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory), +        // QSFactory will not be able to create a tile and getTile will return null +        if (tile != null) { +            showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0}); +        }      }      private QSTile getTile(String subPanel) { @@ -353,12 +357,21 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne          if (mListening) {              refreshAllTiles();          } -        if (mBrightnessView.getVisibility() == View.VISIBLE) { -            if (listening) { -                mBrightnessController.registerCallbacks(); -            } else { -                mBrightnessController.unregisterCallbacks(); -            } +    } + +    public void setListening(boolean listening, boolean expanded) { +        setListening(listening && expanded); +        getFooter().setListening(listening); +        // Set the listening as soon as the QS fragment starts listening regardless of the expansion, +        // so it will update the current brightness before the slider is visible. +        setBrightnessListening(listening); +    } + +    public void setBrightnessListening(boolean listening) { +        if (listening) { +            mBrightnessController.registerCallbacks(); +        } else { +            mBrightnessController.unregisterCallbacks();          }      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 86e69e34fb9e..cefeeb526968 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -31,7 +31,7 @@ import android.util.Log;  import com.android.systemui.Dependency;  import com.android.systemui.R;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.plugins.qs.QSFactory;  import com.android.systemui.plugins.qs.QSTileView;  import com.android.systemui.plugins.qs.QSTile; diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 01ff72e6d152..e884302af075 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -103,8 +103,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {          // it will show all its tiles. In this case, the tiles have to be entered before the          // container is measured. Any change in the tiles, should trigger a remeasure.          final int numTiles = mRecords.size(); -        final int width = MeasureSpec.getSize(widthMeasureSpec) -                - getPaddingStart() - getPaddingEnd(); +        final int width = MeasureSpec.getSize(widthMeasureSpec);          final int heightMode = MeasureSpec.getMode(heightMeasureSpec);          if (heightMode == MeasureSpec.UNSPECIFIED) {              mRows = (numTiles + mColumns - 1) / mColumns; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 12daff1f12f9..9edd65e14bf2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager;  import android.graphics.drawable.Drawable;  import android.nfc.NfcAdapter;  import android.provider.Settings; +import android.service.quicksettings.Tile;  import android.widget.Switch;  import com.android.internal.logging.MetricsLogger; @@ -77,6 +78,9 @@ public class NfcTile extends QSTileImpl<BooleanState> {      @Override      protected void handleClick() { +        if (getAdapter() == null) { +            return; +        }          if (!getAdapter().isEnabled()) {              getAdapter().enable();          } else { @@ -96,13 +100,13 @@ public class NfcTile extends QSTileImpl<BooleanState> {      @Override      protected void handleUpdateState(BooleanState state, Object arg) { -        final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled); -        final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled); - -        if (getAdapter() == null) return; -        state.value = getAdapter().isEnabled(); +        state.value = getAdapter() != null && getAdapter().isEnabled(); +        state.state = getAdapter() == null +                ? Tile.STATE_UNAVAILABLE +                : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; +        state.icon = ResourceIcon.get( +                state.value ? R.drawable.ic_qs_nfc_enabled : R.drawable.ic_qs_nfc_disabled);          state.label = mContext.getString(R.string.quick_settings_nfc_label); -        state.icon = new DrawableIcon(state.value ? mEnable : mDisable);          state.expandedAccessibilityClassName = Switch.class.getName();          state.contentDescription = state.label;      } diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl index fc1831d55c9d..90c10992bc94 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl +++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl @@ -31,8 +31,7 @@ oneway interface IRecentsNonSystemUserCallbacks {      void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);      void toggleRecents(int recentsGrowTarget);      void onConfigurationChanged(); -    void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode, -            in Rect initialBounds); +    void splitPrimaryTask(int topTaskId, int stackCreateMode, in Rect initialBounds);      void onDraggingInRecents(float distanceFromTop);      void onDraggingInRecentsEnded(float velocity);      void showCurrentUserToast(int msgResId, int msgLength); diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl index 58d8d8fd600a..e97714486dcf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl +++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl @@ -29,7 +29,7 @@ oneway interface IRecentsSystemUserCallbacks {      void updateRecentsVisibility(boolean visible);      void startScreenPinning(int taskId);      void sendRecentsDrawnEvent(); -    void sendDockingTopTaskEvent(int dragMode, in Rect initialRect); +    void sendDockingTopTaskEvent(in Rect initialRect);      void sendLaunchRecentsEvent();      void sendDockedFirstAnimationFrameEvent();      void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 8bb3c0231a76..74f6c2dec4e7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -53,6 +53,7 @@ import com.android.systemui.OverviewProxyService;  import com.android.systemui.R;  import com.android.systemui.RecentsComponent;  import com.android.systemui.SystemUIApplication; +import com.android.systemui.recents.events.ui.RecentsGrowingEvent;  import com.android.systemui.shared.recents.IOverviewProxy;  import com.android.systemui.SystemUI;  import com.android.systemui.recents.events.EventBus; @@ -248,6 +249,10 @@ public class Recents extends SystemUI          mImpl.onBootCompleted();      } +    public void growRecents() { +        EventBus.getDefault().send(new RecentsGrowingEvent()); +    } +      /**       * Shows the Recents.       */ @@ -463,7 +468,7 @@ public class Recents extends SystemUI      }      @Override -    public boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds, +    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,              int metricsDockAction) {          // Ensure the device has been provisioned before allowing the user to interact with          // recents @@ -495,16 +500,15 @@ public class Recents extends SystemUI                              runningTask.topActivity.flattenToShortString());                  }                  if (sSystemServicesProxy.isSystemUser(currentUser)) { -                    mImpl.splitPrimaryTask(runningTask.id, dragMode, stackCreateMode, -                            initialBounds); +                    mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds);                  } else {                      if (mSystemToUserCallbacks != null) {                          IRecentsNonSystemUserCallbacks callbacks =                                  mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);                          if (callbacks != null) {                              try { -                                callbacks.splitPrimaryTask(runningTask.id, dragMode, -                                        stackCreateMode, initialBounds); +                                callbacks.splitPrimaryTask(runningTask.id, stackCreateMode, +                                        initialBounds);                              } catch (RemoteException e) {                                  Log.e(TAG, "Callback failed", e);                              } @@ -552,53 +556,6 @@ public class Recents extends SystemUI          }      } -    @Override -    public void onDraggingInRecents(float distanceFromTop) { -        if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) { -            mImpl.onDraggingInRecents(distanceFromTop); -        } else { -            if (mSystemToUserCallbacks != null) { -                IRecentsNonSystemUserCallbacks callbacks = -                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser( -                                mDraggingInRecentsCurrentUser); -                if (callbacks != null) { -                    try { -                        callbacks.onDraggingInRecents(distanceFromTop); -                    } catch (RemoteException e) { -                        Log.e(TAG, "Callback failed", e); -                    } -                } else { -                    Log.e(TAG, "No SystemUI callbacks found for user: " -                            + mDraggingInRecentsCurrentUser); -                } -            } -        } -    } - -    @Override -    public void onDraggingInRecentsEnded(float velocity) { -        if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) { -            mImpl.onDraggingInRecentsEnded(velocity); -        } else { -            if (mSystemToUserCallbacks != null) { -                IRecentsNonSystemUserCallbacks callbacks = -                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser( -                                mDraggingInRecentsCurrentUser); -                if (callbacks != null) { -                    try { -                        callbacks.onDraggingInRecentsEnded(velocity); -                    } catch (RemoteException e) { -                        Log.e(TAG, "Callback failed", e); -                    } -                } else { -                    Log.e(TAG, "No SystemUI callbacks found for user: " -                            + mDraggingInRecentsCurrentUser); -                } -            } -        } -    } - -    @Override      public void showNextAffiliatedTask() {          // Ensure the device has been provisioned before allowing the user to interact with          // recents @@ -609,7 +566,6 @@ public class Recents extends SystemUI          mImpl.showNextAffiliatedTask();      } -    @Override      public void showPrevAffiliatedTask() {          // Ensure the device has been provisioned before allowing the user to interact with          // recents @@ -686,7 +642,12 @@ public class Recents extends SystemUI      public final void onBusEvent(DockedFirstAnimationFrameEvent event) {          SystemServicesProxy ssp = Recents.getSystemServices();          int processUser = ssp.getProcessUser(); -        if (!ssp.isSystemUser(processUser)) { +        if (ssp.isSystemUser(processUser)) { +            final Divider divider = getComponent(Divider.class); +            if (divider != null) { +                divider.onDockedFirstAnimationFrame(); +            } +        } else {              postToSystemUser(new Runnable() {                  @Override                  public void run() { @@ -723,7 +684,12 @@ public class Recents extends SystemUI      public final void onBusEvent(final RecentsDrawnEvent event) {          int processUser = sSystemServicesProxy.getProcessUser(); -        if (!sSystemServicesProxy.isSystemUser(processUser)) { +        if (sSystemServicesProxy.isSystemUser(processUser)) { +            final Divider divider = getComponent(Divider.class); +            if (divider != null) { +                divider.onRecentsDrawn(); +            } +        } else {              postToSystemUser(new Runnable() {                  @Override                  public void run() { @@ -739,13 +705,17 @@ public class Recents extends SystemUI      public final void onBusEvent(final DockedTopTaskEvent event) {          int processUser = sSystemServicesProxy.getProcessUser(); -        if (!sSystemServicesProxy.isSystemUser(processUser)) { +        if (sSystemServicesProxy.isSystemUser(processUser)) { +            final Divider divider = getComponent(Divider.class); +            if (divider != null) { +                divider.onDockedTopTask(); +            } +        } else {              postToSystemUser(new Runnable() {                  @Override                  public void run() {                      try { -                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode, -                                event.initialRect); +                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect);                      } catch (RemoteException e) {                          Log.e(TAG, "Callback failed", e);                      } @@ -756,7 +726,12 @@ public class Recents extends SystemUI      public final void onBusEvent(final RecentsActivityStartingEvent event) {          int processUser = sSystemServicesProxy.getProcessUser(); -        if (!sSystemServicesProxy.isSystemUser(processUser)) { +        if (sSystemServicesProxy.isSystemUser(processUser)) { +            final Divider divider = getComponent(Divider.class); +            if (divider != null) { +                divider.onRecentsActivityStarting(); +            } +        } else {              postToSystemUser(new Runnable() {                  @Override                  public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 63a65d030f6d..d95c7313a282 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -49,6 +49,7 @@ import android.widget.Toast;  import com.android.systemui.Dependency;  import com.android.systemui.OverviewProxyService;  import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.pip.phone.ForegroundThread;  import com.google.android.collect.Lists;  import com.android.internal.logging.MetricsLogger; @@ -72,7 +73,6 @@ import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;  import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;  import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;  import com.android.systemui.recents.misc.DozeTrigger; -import com.android.systemui.recents.misc.ForegroundThread;  import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; @@ -690,14 +690,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener          showRelativeAffiliatedTask(false);      } -    public void splitPrimaryTask(int taskId, int dragMode, int stackCreateMode, -            Rect initialBounds) { +    public void splitPrimaryTask(int taskId, int stackCreateMode, Rect initialBounds) {          SystemServicesProxy ssp = Recents.getSystemServices();          // Make sure we inform DividerView before we actually start the activity so we can change          // the resize mode already.          if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) { -            EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds)); +            EventBus.getDefault().send(new DockedTopTaskEvent(initialBounds));          }      } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java index beec4b395e9c..a1da785f2a80 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java @@ -87,12 +87,11 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {      }      @Override -    public void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode, -            Rect initialBounds) throws RemoteException { +    public void splitPrimaryTask(int topTaskId, int stackCreateMode, Rect initialBounds) +            throws RemoteException {          SomeArgs args = SomeArgs.obtain();          args.argi1 = topTaskId; -        args.argi2 = dragMode; -        args.argi3 = stackCreateMode; +        args.argi2 = stackCreateMode;          args.arg1 = initialBounds;          mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args));      } @@ -141,7 +140,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {                      break;                  case MSG_DOCK_TOP_TASK:                      args = (SomeArgs) msg.obj; -                    mImpl.splitPrimaryTask(args.argi1, args.argi2, args.argi3 = 0, +                    mImpl.splitPrimaryTask(args.argi1, args.argi2 = 0,                              (Rect) args.arg1);                      break;                  case MSG_ON_DRAGGING_IN_RECENTS: diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java index ff1f7dc5a2a8..c5e9f046aa16 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java @@ -26,13 +26,13 @@ import android.util.SparseArray;  import com.android.systemui.EventLogConstants;  import com.android.systemui.EventLogTags; +import com.android.systemui.pip.phone.ForegroundThread;  import com.android.systemui.recents.events.EventBus;  import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;  import com.android.systemui.recents.events.activity.DockedTopTaskEvent;  import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;  import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;  import com.android.systemui.recents.events.ui.RecentsDrawnEvent; -import com.android.systemui.recents.misc.ForegroundThread;  /**   * An implementation of the system user's Recents interface to be called remotely by secondary @@ -99,8 +99,8 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {      }      @Override -    public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException { -        EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect)); +    public void sendDockingTopTaskEvent(Rect initialRect) throws RemoteException { +        EventBus.getDefault().post(new DockedTopTaskEvent(initialRect));      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java index f1bc214670f5..9e3ced3f3757 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java @@ -26,11 +26,9 @@ import com.android.systemui.recents.events.EventBus;   */  public class DockedTopTaskEvent extends EventBus.Event { -    public int dragMode;      public Rect initialRect; -    public DockedTopTaskEvent(int dragMode, Rect initialRect) { -        this.dragMode = dragMode; +    public DockedTopTaskEvent(Rect initialRect) {          this.initialRect = initialRect;      }  } diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 117872558f7f..3ed5f70b8915 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -460,7 +460,7 @@ public class BrightnessController implements ToggleSlider.Listener {      private void animateSliderTo(int target) {          if (!mControlValueInitialized) { -            // Don't animate the first value since it's default state isn't meaningful to users. +            // Don't animate the first value since its default state isn't meaningful to users.              mControl.setValue(target);              mControlValueInitialized = true;          } @@ -470,10 +470,12 @@ public class BrightnessController implements ToggleSlider.Listener {          mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target);          mSliderAnimator.addUpdateListener((ValueAnimator animation) -> {              mExternalChange = true; -            mControl.setValue((int)animation.getAnimatedValue()); +            mControl.setValue((int) animation.getAnimatedValue());              mExternalChange = false;          }); -        mSliderAnimator.setDuration(SLIDER_ANIMATION_DURATION); +        final long animationDuration = SLIDER_ANIMATION_DURATION * Math.abs( +                mControl.getValue() - target) / GAMMA_SPACE_MAX; +        mSliderAnimator.setDuration(animationDuration);          mSliderAnimator.start();      } diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 750002cbc5ca..64fa8f86c5f6 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -18,11 +18,7 @@ package com.android.systemui.shortcut;  import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;  import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -import static android.os.UserHandle.USER_CURRENT; -import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE; - -import android.app.ActivityManager;  import android.content.res.Configuration;  import android.os.RemoteException;  import android.util.Log; @@ -30,17 +26,11 @@ import android.view.IWindowManager;  import android.view.KeyEvent;  import android.view.WindowManager;  import android.view.WindowManagerGlobal; -  import com.android.internal.policy.DividerSnapAlgorithm;  import com.android.systemui.SystemUI;  import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.shared.system.ActivityManagerWrapper;  import com.android.systemui.stackdivider.Divider;  import com.android.systemui.stackdivider.DividerView; -import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; - -import java.util.List;  /**   * Dispatches shortcut to System UI components @@ -94,7 +84,7 @@ public class ShortcutKeyDispatcher extends SystemUI              if (dockSide == WindowManager.DOCKED_INVALID) {                  // Split the screen                  Recents recents = getComponent(Recents.class); -                recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT) +                recents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)                          ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT                          : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);              } else { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index da0a43551f1f..ea194a70adf2 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -16,29 +16,28 @@  package com.android.systemui.stackdivider; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +  import android.content.res.Configuration;  import android.os.RemoteException; +import android.util.Log;  import android.view.IDockedStackListener;  import android.view.LayoutInflater;  import android.view.View; - +import android.view.WindowManagerGlobal;  import com.android.systemui.R;  import com.android.systemui.SystemUI;  import com.android.systemui.recents.Recents; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.ui.RecentsDrawnEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; - -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -  import java.io.FileDescriptor;  import java.io.PrintWriter;  /**   * Controls the docked stack divider.   */ -public class Divider extends SystemUI { +public class Divider extends SystemUI implements DividerView.DividerCallbacks { +    private static final String TAG = "Divider"; +      private DividerWindowManager mWindowManager;      private DividerView mView;      private final DividerState mDividerState = new DividerState(); @@ -55,10 +54,13 @@ public class Divider extends SystemUI {          update(mContext.getResources().getConfiguration());          putComponent(Divider.class, this);          mDockDividerVisibilityListener = new DockDividerVisibilityListener(); -        SystemServicesProxy ssp = Recents.getSystemServices(); -        ssp.registerDockedStackListener(mDockDividerVisibilityListener); +        try { +            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener( +                    mDockDividerVisibilityListener); +        } catch (Exception e) { +            Log.e(TAG, "Failed to register docked stack listener", e); +        }          mForcedResizableController = new ForcedResizableInfoActivityController(mContext); -        EventBus.getDefault().register(this);      }      @Override @@ -82,7 +84,7 @@ public class Divider extends SystemUI {      private void addDivider(Configuration configuration) {          mView = (DividerView)                  LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null); -        mView.injectDependencies(mWindowManager, mDividerState); +        mView.injectDependencies(mWindowManager, mDividerState, this);          mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);          mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);          final int size = mContext.getResources().getDimensionPixelSize( @@ -156,18 +158,64 @@ public class Divider extends SystemUI {          mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);      } +    public void onRecentsActivityStarting() { +        if (mView != null) { +            mView.onRecentsActivityStarting(); +        } +    } +      /** -     * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a +     * Workaround for b/62528361, at the time recents has drawn, it may happen before a       * configuration change to the Divider, and internally, the event will be posted to the       * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,       * register the event handler here and proxy the event to the current DividerView.       */ -    public final void onBusEvent(RecentsDrawnEvent drawnEvent) { +    public void onRecentsDrawn() {          if (mView != null) {              mView.onRecentsDrawn();          }      } +    public void onUndockingTask() { +        if (mView != null) { +            mView.onUndockingTask(); +        } +    } + +    public void onDockedFirstAnimationFrame() { +        if (mView != null) { +            mView.onDockedFirstAnimationFrame(); +        } +    } + +    public void onDockedTopTask() { +        if (mView != null) { +            mView.onDockedTopTask(); +        } +    } + +    public void onAppTransitionFinished() { +        mForcedResizableController.onAppTransitionFinished(); +    } + +    @Override +    public void onDraggingStart() { +        mForcedResizableController.onDraggingStart(); +    } + +    @Override +    public void onDraggingEnd() { +        mForcedResizableController.onDraggingEnd(); +    } + +    @Override +    public void growRecents() { +        Recents recents = getComponent(Recents.class); +        if (recents != null) { +            recents.growRecents(); +        } +    } +      @Override      public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {          pw.print("  mVisible="); pw.println(mVisible); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 98925b9ba9e5..fa01af68364e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -55,7 +55,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;  import android.view.animation.Interpolator;  import android.view.animation.PathInterpolator;  import android.widget.FrameLayout; -  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.nano.MetricsProto.MetricsEvent;  import com.android.internal.policy.DividerSnapAlgorithm; @@ -64,17 +63,8 @@ import com.android.internal.policy.DockedDividerUtils;  import com.android.internal.view.SurfaceFlingerVsyncChoreographer;  import com.android.systemui.Interpolators;  import com.android.systemui.R; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; -import com.android.systemui.recents.events.activity.DockedTopTaskEvent; -import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; -import com.android.systemui.recents.events.activity.UndockingTaskEvent; -import com.android.systemui.recents.events.ui.RecentsGrowingEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.stackdivider.events.StartedDragingEvent; -import com.android.systemui.stackdivider.events.StoppedDragingEvent; +import com.android.systemui.shared.system.WindowManagerWrapper;  import com.android.systemui.statusbar.FlingAnimationUtils; -import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;  /**   * Docked stack divider. @@ -82,6 +72,12 @@ import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;  public class DividerView extends FrameLayout implements OnTouchListener,          OnComputeInternalInsetsListener { +    public interface DividerCallbacks { +        void onDraggingStart(); +        void onDraggingEnd(); +        void growRecents(); +    } +      static final long TOUCH_ANIMATION_DURATION = 150;      static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; @@ -149,6 +145,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,      private FlingAnimationUtils mFlingAnimationUtils;      private DividerSnapAlgorithm mSnapAlgorithm;      private DividerSnapAlgorithm mMinimizedSnapAlgorithm; +    private DividerCallbacks mCallback;      private final Rect mStableInsets = new Rect();      private boolean mGrowRecents; @@ -162,6 +159,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,      private DividerState mState;      private final SurfaceFlingerVsyncChoreographer mSfChoreographer; +      // The view is removed or in the process of been removed from the system.      private boolean mRemoved; @@ -306,7 +304,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,      @Override      protected void onAttachedToWindow() {          super.onAttachedToWindow(); -        EventBus.getDefault().register(this);          // Save the current target if not minimized once attached to window          if (mHomeStackResizable && mDockSide != WindowManager.DOCKED_INVALID @@ -315,14 +312,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,          }      } -    @Override -    protected void onDetachedFromWindow() { -        super.onDetachedFromWindow(); -        EventBus.getDefault().unregister(this); -    } -      void onDividerRemoved() {          mRemoved = true; +        mCallback = null;          mHandler.removeMessages(MSG_RESIZE_STACK);      } @@ -364,13 +356,15 @@ public class DividerView extends FrameLayout implements OnTouchListener,          }      } -    public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState) { +    public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState, +            DividerCallbacks callback) {          mWindowManager = windowManager;          mState = dividerState; +        mCallback = callback;          // Set the previous position ratio before minimized state after attaching this divider          if (mStableInsets.isEmpty()) { -            SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); +            WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);          }          if (mState.mRatioPositionBeforeMinimized == 0) { @@ -419,7 +413,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,              mWindowManager.setSlippery(false);              liftBackground();          } -        EventBus.getDefault().send(new StartedDragingEvent()); +        if (mCallback != null) { +            mCallback.onDraggingStart(); +        }          return mDockSide != WindowManager.DOCKED_INVALID;      } @@ -617,7 +613,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,              mCurrentAnimator = null;              mEntranceAnimationRunning = false;              mExitAnimationRunning = false; -            EventBus.getDefault().send(new StoppedDragingEvent()); +            if (mCallback != null) { +                mCallback.onDraggingEnd(); +            }              // Record last snap target the divider moved to              if (mHomeStackResizable && !mIsInMinimizeInteraction) { @@ -776,7 +774,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,              if (mDisplayRotation != mDefaultDisplay.getRotation()) {                  // Splitscreen to minimize is about to starts after rotating landscape to seascape,                  // update insets, display info and snap algorithm targets -                SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); +                WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);                  repositionSnapTargetBeforeMinimized();                  updateDisplayInfo();              } else { @@ -910,7 +908,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,          requestLayout();          // Update the snap position to the new docked side with correct insets -        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); +        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);          mMinimizedSnapAlgorithm = null;          initializeSnapAlgorithm(); @@ -1271,7 +1269,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,          }      } -    public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) { +    void onRecentsActivityStarting() {          if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP                  && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()                  && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) { @@ -1280,16 +1278,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,          }      } -    public final void onBusEvent(DockedFirstAnimationFrameEvent event) { +    void onDockedFirstAnimationFrame() {          saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget());      } -    public final void onBusEvent(DockedTopTaskEvent event) { -        if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) { -            mState.growAfterRecentsDrawn = false; -            mState.animateAfterRecentsDrawn = true; -            startDragging(false /* animate */, false /* touching */); -        } +    void onDockedTopTask() { +        mState.growAfterRecentsDrawn = false; +        mState.animateAfterRecentsDrawn = true; +        startDragging(false /* animate */, false /* touching */);          updateDockSide();          mEntranceAnimationRunning = true; @@ -1297,7 +1293,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,                  mSnapAlgorithm.getMiddleTarget());      } -    public void onRecentsDrawn() { +    void onRecentsDrawn() {          updateDockSide();          final int position = calculatePositionForInsetBounds();          if (mState.animateAfterRecentsDrawn) { @@ -1314,13 +1310,15 @@ public class DividerView extends FrameLayout implements OnTouchListener,          if (mState.growAfterRecentsDrawn) {              mState.growAfterRecentsDrawn = false;              updateDockSide(); -            EventBus.getDefault().send(new RecentsGrowingEvent()); +            if (mCallback != null) { +                mCallback.growRecents(); +            }              stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,                      Interpolators.FAST_OUT_SLOW_IN);          }      } -    public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) { +    void onUndockingTask() {          int dockSide = mWindowManagerProxy.getDockSide();          if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable                  || !mDockedStackMinimized)) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java index 4415bd7a631b..02f75050c061 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java @@ -52,7 +52,7 @@ public class ForcedResizableInfoActivity extends Activity implements OnTouchList      protected void onCreate(@Nullable Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.forced_resizable_activity); -        TextView tv = (TextView) findViewById(com.android.internal.R.id.message); +        TextView tv = findViewById(com.android.internal.R.id.message);          int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1);          String text;          switch (reason) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java index 826fa6cefccc..f66db48f441c 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java @@ -16,8 +16,7 @@  package com.android.systemui.stackdivider; -import static com.android.systemui.stackdivider.ForcedResizableInfoActivity -        .EXTRA_FORCED_RESIZEABLE_REASON; +import static com.android.systemui.stackdivider.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON;  import android.app.ActivityOptions;  import android.content.Context; @@ -26,16 +25,9 @@ import android.os.Handler;  import android.os.UserHandle;  import android.util.ArraySet;  import android.widget.Toast; -  import com.android.systemui.R; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; -import com.android.systemui.recents.events.component.ShowUserToastEvent; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.stackdivider.events.StartedDragingEvent; -import com.android.systemui.stackdivider.events.StoppedDragingEvent; +import com.android.systemui.shared.system.TaskStackChangeListener;  /**   * Controller that decides when to show the {@link ForcedResizableInfoActivity}. @@ -49,7 +41,7 @@ public class ForcedResizableInfoActivityController {      private final Handler mHandler = new Handler();      private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();      private final ArraySet<String> mPackagesShownInSession = new ArraySet<>(); -    private boolean mDividerDraging; +    private boolean mDividerDragging;      private final Runnable mTimeoutRunnable = new Runnable() {          @Override @@ -75,9 +67,8 @@ public class ForcedResizableInfoActivityController {      public ForcedResizableInfoActivityController(Context context) {          mContext = context; -        EventBus.getDefault().register(this);          ActivityManagerWrapper.getInstance().registerTaskStackListener( -                new SysUiTaskStackChangeListener() { +                new TaskStackChangeListener() {                      @Override                      public void onActivityForcedResizable(String packageName, int taskId,                              int reason) { @@ -102,19 +93,19 @@ public class ForcedResizableInfoActivityController {          }      } -    public final void onBusEvent(AppTransitionFinishedEvent event) { -        if (!mDividerDraging) { +    public void onAppTransitionFinished() { +        if (!mDividerDragging) {              showPending();          }      } -    public final void onBusEvent(StartedDragingEvent event) { -        mDividerDraging = true; +    void onDraggingStart() { +        mDividerDragging = true;          mHandler.removeCallbacks(mTimeoutRunnable);      } -    public final void onBusEvent(StoppedDragingEvent event) { -        mDividerDraging = false; +    void onDraggingEnd() { +        mDividerDragging = false;          showPending();      } @@ -127,13 +118,13 @@ public class ForcedResizableInfoActivityController {      }      private void activityDismissingDockedStack() { -        EventBus.getDefault().send(new ShowUserToastEvent( -                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT)); +        Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, +                Toast.LENGTH_SHORT).show();      }      private void activityLaunchOnSecondaryDisplayFailed() { -        EventBus.getDefault().send(new ShowUserToastEvent( -                R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT)); +        Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text, +                Toast.LENGTH_SHORT).show();      }      private void showPending() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 247e3d342bbb..00e0b954d7be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -16,6 +16,10 @@  package com.android.systemui.statusbar; +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; +  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.AlertDialog; @@ -30,10 +34,10 @@ import android.content.pm.IPackageManager;  import android.content.pm.PackageInfo;  import android.content.pm.ResolveInfo;  import android.content.res.ColorStateList; -import android.graphics.drawable.Icon;  import android.graphics.Bitmap;  import android.graphics.Canvas;  import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon;  import android.hardware.input.InputManager;  import android.os.Handler;  import android.os.Looper; @@ -51,29 +55,23 @@ import android.view.View;  import android.view.View.AccessibilityDelegate;  import android.view.ViewGroup;  import android.view.Window; +import android.view.WindowManager;  import android.view.WindowManager.KeyboardShortcutsReceiver;  import android.view.accessibility.AccessibilityNodeInfo;  import android.widget.ImageView;  import android.widget.LinearLayout;  import android.widget.RelativeLayout;  import android.widget.TextView; -  import com.android.internal.app.AssistUtils;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.nano.MetricsProto;  import com.android.settingslib.Utils;  import com.android.systemui.R; -import com.android.systemui.recents.misc.SystemServicesProxy; -  import java.util.ArrayList;  import java.util.Collections;  import java.util.Comparator;  import java.util.List; -import static android.content.Context.LAYOUT_INFLATER_SERVICE; -import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; -  /**   * Contains functionality for handling keyboard shortcuts.   */ @@ -372,19 +370,19 @@ public final class KeyboardShortcuts {      private void showKeyboardShortcuts(int deviceId) {          retrieveKeyCharacterMap(deviceId); -        SystemServicesProxy.getInstance(mContext).requestKeyboardShortcuts(mContext, -                new KeyboardShortcutsReceiver() { -                    @Override -                    public void onKeyboardShortcutsReceived( -                            final List<KeyboardShortcutGroup> result) { -                        result.add(getSystemShortcuts()); -                        final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts(); -                        if (appShortcuts != null) { -                            result.add(appShortcuts); -                        } -                        showKeyboardShortcutsDialog(result); -                    } -                }, deviceId); +        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); +        wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() { +            @Override +            public void onKeyboardShortcutsReceived( +                    final List<KeyboardShortcutGroup> result) { +                result.add(getSystemShortcuts()); +                final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts(); +                if (appShortcuts != null) { +                    result.add(appShortcuts); +                } +                showKeyboardShortcutsDialog(result); +            } +        }, deviceId);      }      private void dismissKeyboardShortcuts() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 304a00fbba4a..2450e448c4f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -17,7 +17,6 @@  package com.android.systemui.statusbar.car;  import android.app.ActivityTaskManager; -import android.car.user.CarUserManagerHelper;  import android.graphics.PixelFormat;  import android.graphics.drawable.Drawable;  import android.util.Log; @@ -36,8 +35,8 @@ import com.android.systemui.classifier.FalsingLog;  import com.android.systemui.classifier.FalsingManager;  import com.android.systemui.fragments.FragmentHostManager;  import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.car.hvac.HvacController;  import com.android.systemui.statusbar.car.hvac.TemperatureView; @@ -461,16 +460,11 @@ public class CarStatusBar extends StatusBar implements          }      } - -    public boolean hasDockedTask() { -        return Recents.getSystemServices().hasDockedTask(); -    } -      /** -     * An implementation of SysUiTaskStackChangeListener, that listens for changes in the system +     * An implementation of TaskStackChangeListener, that listens for changes in the system       * task stack and notifies the navigation bar.       */ -    private class TaskStackListenerImpl extends SysUiTaskStackChangeListener { +    private class TaskStackListenerImpl extends TaskStackChangeListener {          @Override          public void onTaskStackChanged() {              try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index 67e512cf23f9..618a4c134049 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -22,7 +22,7 @@ import static android.content.DialogInterface.BUTTON_POSITIVE;  import android.app.AlertDialog;  import android.app.AlertDialog.Builder;  import android.app.Dialog; -import android.car.user.CarUserManagerHelper; +import android.car.userlib.CarUserManagerHelper;  import android.content.Context;  import android.content.DialogInterface;  import android.content.pm.UserInfo; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index d5a52740c6d4..a3e982e77522 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -35,6 +35,8 @@ import android.os.ServiceManager;  import android.os.SystemClock;  import android.os.UserHandle;  import android.provider.Settings; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager;  import android.service.notification.NotificationListenerService;  import android.service.notification.NotificationStats;  import android.service.notification.StatusBarNotification; @@ -58,7 +60,6 @@ import com.android.systemui.EventLogTags;  import com.android.systemui.ForegroundServiceController;  import com.android.systemui.R;  import com.android.systemui.UiOffloadThread; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.statusbar.NotificationLifetimeExtender;  import com.android.systemui.statusbar.AlertingNotificationManager;  import com.android.systemui.statusbar.AmbientPulseManager; @@ -127,11 +128,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.              Dependency.get(NotificationListener.class);      protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class); +    protected IDreamManager mDreamManager;      protected IStatusBarService mBarService;      protected NotificationPresenter mPresenter;      protected Callback mCallback;      protected PowerManager mPowerManager; -    protected SystemServicesProxy mSystemServicesProxy;      protected NotificationListenerService.RankingMap mLatestRankingMap;      protected HeadsUpManager mHeadsUpManager;      protected NotificationData mNotificationData; @@ -223,8 +224,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.          mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);          mBarService = IStatusBarService.Stub.asInterface(                  ServiceManager.getService(Context.STATUS_BAR_SERVICE)); +        mDreamManager = IDreamManager.Stub.asInterface( +                ServiceManager.checkService(DreamService.DREAM_SERVICE));          mMessagingUtil = new NotificationMessagingUtil(context); -        mSystemServicesProxy = SystemServicesProxy.getInstance(mContext);          mGroupManager.setPendingEntries(mPendingNotifications);      } @@ -687,7 +689,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.              } else {                  // Stop screensaver if the notification has a fullscreen intent.                  // (like an incoming phone call) -                SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); +                Dependency.get(UiOffloadThread.class).submit(() -> { +                    try { +                        mDreamManager.awaken(); +                    } catch (RemoteException e) { +                        e.printStackTrace(); +                    } +                });                  // not immersive & a fullscreen alert should be shown                  if (DEBUG) @@ -898,7 +906,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.              return false;          } -        boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming(); +        boolean isDreaming = false; +        try { +            isDreaming = mDreamManager.isDreaming(); +        } catch (RemoteException e) { +            Log.e(TAG, "Failed to query dream manager.", e); +        } +        boolean inUse = mPowerManager.isScreenOn() && !isDreaming;          if (!inUse) {              if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 9b1d334c614d..bce613a33859 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -72,7 +72,7 @@ import com.android.systemui.Interpolators;  import com.android.systemui.R;  import com.android.systemui.classifier.FalsingManager;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;  import com.android.systemui.statusbar.notification.NotificationData; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 72c2c0bec31f..9978ec364cdb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -87,7 +87,6 @@ import com.android.systemui.classifier.FalsingManager;  import com.android.systemui.colorextraction.SysuiColorExtractor;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;  import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; -import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;  import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.DragDownHelper.DragDownCallback; @@ -109,6 +108,7 @@ import com.android.systemui.statusbar.notification.NotificationData;  import com.android.systemui.statusbar.notification.row.NotificationGuts;  import com.android.systemui.statusbar.notification.logging.NotificationLogger;  import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager;  import com.android.systemui.statusbar.notification.row.NotificationSnooze;  import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;  import com.android.systemui.statusbar.StatusBarStateController; @@ -146,11 +146,9 @@ import java.util.function.BiConsumer;   * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.   */  public class NotificationStackScrollLayout extends ViewGroup -        implements Callback, ExpandHelper.Callback, ScrollAdapter, -        OnHeightChangedListener, OnGroupChangeListener, -        OnMenuEventListener, VisibilityLocationProvider, -        NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler, -        Dumpable { +        implements ExpandHelper.Callback, ScrollAdapter, OnHeightChangedListener, +        OnGroupChangeListener, VisibilityLocationProvider, NotificationListContainer, +        ConfigurationListener, DragDownCallback, AnimationStateHandler, Dumpable {      public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;      private static final String TAG = "StackScroller"; @@ -164,7 +162,7 @@ public class NotificationStackScrollLayout extends ViewGroup      private static final int INVALID_POINTER = -1;      private ExpandHelper mExpandHelper; -    private NotificationSwipeHelper mSwipeHelper; +    private final NotificationSwipeHelper mSwipeHelper;      private boolean mSwipingInProgress;      private int mCurrentStackHeight = Integer.MAX_VALUE;      private final Paint mBackgroundPaint = new Paint(); @@ -291,10 +289,6 @@ public class NotificationStackScrollLayout extends ViewGroup       */      private int mMaxScrollAfterExpand;      private ExpandableNotificationRow.LongPressListener mLongPressListener; - -    private NotificationMenuRowPlugin mCurrMenuRow; -    private View mTranslatingParentView; -    private View mMenuExposedView;      boolean mCheckForLeavebehind;      /** @@ -466,6 +460,9 @@ public class NotificationStackScrollLayout extends ViewGroup      private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;      private NotificationPanelView mNotificationPanel; +    private final NotificationGutsManager +            mNotificationGutsManager = Dependency.get(NotificationGutsManager.class); +      @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)      public NotificationStackScrollLayout(Context context) {          this(context, null); @@ -495,7 +492,8 @@ public class NotificationStackScrollLayout extends ViewGroup                  minHeight, maxHeight);          mExpandHelper.setEventSource(this);          mExpandHelper.setScrollAdapter(this); -        mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext()); +        mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, new SwipeHelperCallback(), +                getContext(), new NotificationMenuListener());          mStackScrollAlgorithm = createStackScrollAlgorithm(context);          initView(context);          mFalsingManager = FalsingManager.getInstance(context); @@ -639,41 +637,6 @@ public class NotificationStackScrollLayout extends ViewGroup      }      @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public void onMenuClicked(View view, int x, int y, MenuItem item) { -        if (mLongPressListener == null) { -            return; -        } -        if (view instanceof ExpandableNotificationRow) { -            ExpandableNotificationRow row = (ExpandableNotificationRow) view; -            MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR, -                    row.getStatusBarNotification().getPackageName()); -        } -        mLongPressListener.onLongPress(view, x, y, item); -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public void onMenuReset(View row) { -        if (mTranslatingParentView != null && row == mTranslatingParentView) { -            mMenuExposedView = null; -            mTranslatingParentView = null; -        } -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public void onMenuShown(View row) { -        mMenuExposedView = mTranslatingParentView; -        if (row instanceof ExpandableNotificationRow) { -            MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR, -                    ((ExpandableNotificationRow) row).getStatusBarNotification() -                            .getPackageName()); -        } -        mSwipeHelper.onMenuShown(row); -    } - -    @Override      @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)      public void onUiModeChanged() {          mBgColor = mContext.getColor(R.color.notification_shade_background_color); @@ -1295,111 +1258,6 @@ public class NotificationStackScrollLayout extends ViewGroup          mQsContainer = qsContainer;      } -    /** -     * Handles cleanup after the given {@code view} has been fully swiped out (including -     * re-invoking dismiss logic in case the notification has not made its way out yet). -     */ -    @Override -    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -    public void onChildDismissed(View view) { -        ExpandableNotificationRow row = (ExpandableNotificationRow) view; -        if (!row.isDismissed()) { -            handleChildViewDismissed(view); -        } -        ViewGroup transientContainer = row.getTransientContainer(); -        if (transientContainer != null) { -            transientContainer.removeTransientView(view); -        } -    } - -    /** -     * Starts up notification dismiss and tells the notification, if any, to remove itself from -     * layout. -     * -     * @param view view (e.g. notification) to dismiss from the layout -     */ - -    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -    private void handleChildViewDismissed(View view) { -        if (mDismissAllInProgress) { -            return; -        } - -        boolean isBlockingHelperShown = false; - -        setSwipingInProgress(false); -        if (mDragAnimPendingChildren.contains(view)) { -            // We start the swipe and finish it in the same frame; we don't want a drag animation. -            mDragAnimPendingChildren.remove(view); -        } -        mAmbientState.onDragFinished(view); -        updateContinuousShadowDrawing(); - -        if (view instanceof ExpandableNotificationRow) { -            ExpandableNotificationRow row = (ExpandableNotificationRow) view; -            if (row.isHeadsUp()) { -                mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey()); -            } -            isBlockingHelperShown = -                    row.performDismissWithBlockingHelper(false /* fromAccessibility */); -        } - -        if (!isBlockingHelperShown) { -            mSwipedOutViews.add(view); -        } -        mFalsingManager.onNotificationDismissed(); -        if (mFalsingManager.shouldEnforceBouncer()) { -            mStatusBar.executeRunnableDismissingKeyguard( -                    null, -                    null /* cancelAction */, -                    false /* dismissShade */, -                    true /* afterKeyguardGone */, -                    false /* deferred */); -        } -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -    public void onChildSnappedBack(View animView, float targetLeft) { -        mAmbientState.onDragFinished(animView); -        updateContinuousShadowDrawing(); -        if (!mDragAnimPendingChildren.contains(animView)) { -            if (mAnimationsEnabled) { -                mSnappedBackChildren.add(animView); -                mNeedsAnimation = true; -            } -            requestChildrenUpdate(); -        } else { -            // We start the swipe and snap back in the same frame, we don't want any animation -            mDragAnimPendingChildren.remove(animView); -        } -        if (mCurrMenuRow != null && targetLeft == 0) { -            mCurrMenuRow.resetMenu(); -            mCurrMenuRow = null; -        } -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) { -        // Returning true prevents alpha fading. -        return !mFadeNotificationsOnDismiss; -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public void onBeginDrag(View v) { -        mFalsingManager.onNotificatonStartDismissing(); -        setSwipingInProgress(true); -        mAmbientState.onBeginDrag(v); -        updateContinuousShadowDrawing(); -        if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) { -            mDragAnimPendingChildren.add(v); -            mNeedsAnimation = true; -        } -        requestChildrenUpdate(); -    } -      @ShadeViewRefactor(RefactorComponent.ADAPTER)      public static boolean isPinnedHeadsUp(View v) {          if (v instanceof ExpandableNotificationRow) { @@ -1418,41 +1276,6 @@ public class NotificationStackScrollLayout extends ViewGroup          return false;      } -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public void onDragCancelled(View v) { -        mFalsingManager.onNotificatonStopDismissing(); -        setSwipingInProgress(false); -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public float getFalsingThresholdFactor() { -        return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; -    } - -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public View getChildAtPosition(MotionEvent ev) { -        View child = getChildAtPosition(ev.getX(), ev.getY()); -        if (child instanceof ExpandableNotificationRow) { -            ExpandableNotificationRow row = (ExpandableNotificationRow) child; -            ExpandableNotificationRow parent = row.getNotificationParent(); -            if (parent != null && parent.areChildrenExpanded() -                    && (parent.areGutsExposed() -                    || mMenuExposedView == parent -                    || (parent.getNotificationChildren().size() == 1 -                    && parent.isClearable()))) { -                // In this case the group is expanded and showing the menu for the -                // group, further interaction should apply to the group, not any -                // child notifications so we use the parent of the child. We also do the same -                // if we only have a single child. -                child = parent; -            } -        } -        return child; -    } -      @ShadeViewRefactor(RefactorComponent.INPUT)      public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {          getLocationOnScreen(mTempInt2); @@ -1696,18 +1519,11 @@ public class NotificationStackScrollLayout extends ViewGroup          return mScrollingEnabled;      } -    @Override      @ShadeViewRefactor(RefactorComponent.ADAPTER) -    public boolean canChildBeDismissed(View v) { +    private boolean canChildBeDismissed(View v) {          return StackScrollAlgorithm.canChildBeDismissed(v);      } -    @Override -    @ShadeViewRefactor(RefactorComponent.INPUT) -    public boolean isAntiFalsingNeeded() { -        return onKeyguard(); -    } -      @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)      private boolean onKeyguard() {          return mStatusBarState == StatusBarState.KEYGUARD; @@ -1787,8 +1603,8 @@ public class NotificationStackScrollLayout extends ViewGroup          }          // Check if we need to clear any snooze leavebehinds -        NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts(); -        if (guts != null && !isTouchInView(ev, guts) +        NotificationGuts guts = mNotificationGutsManager.getExposedGuts(); +        if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)                  && guts.getGutsContent() instanceof NotificationSnooze) {              NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();              if ((ns.isExpanded() && isCancelOrUp) @@ -3013,11 +2829,11 @@ public class NotificationStackScrollLayout extends ViewGroup          }          // Check if we need to clear any snooze leavebehinds          boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP; -        NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts(); -        if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt -                && !scrollWantsIt) { +        NotificationGuts guts = mNotificationGutsManager.getExposedGuts(); +        if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt && +                !expandWantsIt && !scrollWantsIt) {              mCheckForLeavebehind = false; -            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */, +            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,                      false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,                      false /* resetMenu */);          } @@ -3077,8 +2893,8 @@ public class NotificationStackScrollLayout extends ViewGroup      @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)      @Override      public void cleanUpViewState(View child) { -        if (child == mTranslatingParentView) { -            mTranslatingParentView = null; +        if (child == mSwipeHelper.getTranslatingParentView()) { +            mSwipeHelper.clearTranslatingParentView();          }          mCurrentStackScrollState.removeViewStateForView(child);      } @@ -3986,7 +3802,7 @@ public class NotificationStackScrollLayout extends ViewGroup      @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)      public void checkSnoozeLeavebehind() {          if (mCheckForLeavebehind) { -            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */, +            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,                      false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,                      false /* resetMenu */);              mCheckForLeavebehind = false; @@ -4068,7 +3884,7 @@ public class NotificationStackScrollLayout extends ViewGroup      }      @ShadeViewRefactor(RefactorComponent.COORDINATOR) -    private void setIsExpanded(boolean isExpanded) { +    public void setIsExpanded(boolean isExpanded) {          boolean changed = isExpanded != mIsExpanded;          mIsExpanded = isExpanded;          mStackScrollAlgorithm.setIsExpanded(isExpanded); @@ -5242,8 +5058,8 @@ public class NotificationStackScrollLayout extends ViewGroup          setFooterView(footerView);      } -  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -  private void inflateEmptyShadeView() { +    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +    private void inflateEmptyShadeView() {          EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(                  R.layout.status_bar_no_notifications, this, false);          view.setText(R.string.empty_shade_text); @@ -5274,8 +5090,8 @@ public class NotificationStackScrollLayout extends ViewGroup          mScrimController.setNotificationCount(getNotGoneChildCount());      } -  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -  public void setNotificationPanel(NotificationPanelView notificationPanelView) { +    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +    public void setNotificationPanel(NotificationPanelView notificationPanelView) {          mNotificationPanel = notificationPanelView;      } @@ -5293,306 +5109,29 @@ public class NotificationStackScrollLayout extends ViewGroup      @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)      public interface OnOverscrollTopChangedListener { -        /** -         * Notifies a listener that the overscroll has changed. -         * -         * @param amount         the amount of overscroll, in pixels -         * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an -         *                       unrubberbanded motion to directly expand overscroll view (e.g -         *                       expand -         *                       QS) -         */ -        void onOverscrollTopChanged(float amount, boolean isRubberbanded); - -        /** -         * Notify a listener that the scroller wants to escape from the scrolling motion and -         * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS) -         * -         * @param velocity The velocity that the Scroller had when over flinging -         * @param open     Should the fling open or close the overscroll view. -         */ -        void flingTopOverscroll(float velocity, boolean open); -    } - -    @ShadeViewRefactor(RefactorComponent.INPUT) -    private class NotificationSwipeHelper extends SwipeHelper -            implements NotificationSwipeActionHelper { -        private static final long COVER_MENU_DELAY = 4000; -        private Runnable mFalsingCheck; -        private Handler mHandler; - -        private static final long SWIPE_MENU_TIMING = 200; - -        public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) { -            super(swipeDirection, callback, context); -            mHandler = new Handler(); -            mFalsingCheck = new Runnable() { -                @Override -                public void run() { -                    resetExposedMenuView(true /* animate */, true /* force */); -                } -            }; -        } - -        @Override -        public void onDownUpdate(View currView, MotionEvent ev) { -            mTranslatingParentView = currView; -            if (mCurrMenuRow != null) { -                mCurrMenuRow.onTouchStart(); -            } -            mCurrMenuRow = null; -            mHandler.removeCallbacks(mFalsingCheck); - -            // Slide back any notifications that might be showing a menu -            resetExposedMenuView(true /* animate */, false /* force */); - -            if (currView instanceof ExpandableNotificationRow) { -                ExpandableNotificationRow row = (ExpandableNotificationRow) currView; - -                if (row.getEntry().hasFinishedInitialization()) { -                    mCurrMenuRow = row.createMenu(); -                    mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this); -                    mCurrMenuRow.onTouchStart(); -                } -            } -        } - -        private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) { -            return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu(); -        } - -        @Override -        public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) { -            mHandler.removeCallbacks(mFalsingCheck); -            if (mCurrMenuRow != null) { -                mCurrMenuRow.onTouchMove(delta); -            } -        } - -        @Override -        public boolean handleUpEvent(MotionEvent ev, View animView, float velocity, -                float translation) { -            if (mCurrMenuRow != null) { -                mCurrMenuRow.onTouchEnd(); -                handleMenuRowSwipe(ev, animView, velocity, mCurrMenuRow); -                return true; -            } -            return false; -        } - -        @Override -        public boolean swipedFarEnough(float translation, float viewSize) { -            return swipedFarEnough(); -        } - -        private void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity, -                NotificationMenuRowPlugin menuRow) { -            if (!menuRow.shouldShowMenu()) { -                // If the menu should not be shown, then there is no need to check if the a swipe -                // should result in a snapping to the menu. As a result, just check if the swipe -                // was enough to dismiss the notification. -                if (isDismissGesture(ev)) { -                    dismiss(animView, velocity); -                } else { -                    snapBack(animView, velocity); -                    menuRow.onSnapClosed(); -                } -                return; -            } - -            if (menuRow.isSnappedAndOnSameSide()) { -                // Menu was snapped to previously and we're on the same side -                handleSwipeFromSnap(ev, animView, velocity, menuRow); -            } else { -                // Menu has not been snapped, or was snapped previously but is now on -                // the opposite side. -                handleSwipeFromNonSnap(ev, animView, velocity, menuRow); -            } -        } - -        private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity, -                NotificationMenuRowPlugin menuRow) { -            boolean isDismissGesture = isDismissGesture(ev); -            final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity); -            final boolean gestureFastEnough = -                    mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity); - -            final double timeForGesture = ev.getEventTime() - ev.getDownTime(); -            final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed() -                    && timeForGesture >= SWIPE_MENU_TIMING; - -            if (!isFalseGesture(ev) -                    && (swipedEnoughToShowMenu(menuRow) -                    && (!gestureFastEnough || showMenuForSlowOnGoing)) -                    || (gestureTowardsMenu && !isDismissGesture)) { -                // Menu has not been snapped to previously and this is menu revealing gesture -                snapOpen(animView, menuRow.getMenuSnapTarget(), velocity); -                menuRow.onSnapOpen(); -            } else if (isDismissGesture(ev) && !gestureTowardsMenu) { -                dismiss(animView, velocity); -                menuRow.onDismiss(); -            } else { -                snapBack(animView, velocity); -                menuRow.onSnapClosed(); -            } -        } - -        private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity, -                NotificationMenuRowPlugin menuRow) { -            boolean isDismissGesture = isDismissGesture(ev); - -            final boolean withinSnapMenuThreshold = -                    menuRow.isWithinSnapMenuThreshold(); - -            if (withinSnapMenuThreshold && !isDismissGesture) { -                // Haven't moved enough to unsnap from the menu -                menuRow.onSnapOpen(); -                snapOpen(animView, menuRow.getMenuSnapTarget(), velocity); -            } else if (isDismissGesture && !menuRow.shouldSnapBack()) { -                // Only dismiss if we're not moving towards the menu -                dismiss(animView, velocity); -                menuRow.onDismiss(); -            } else { -                snapBack(animView, velocity); -                menuRow.onSnapClosed(); -            } -        } - -        @Override -        public void dismissChild(final View view, float velocity, -                boolean useAccelerateInterpolator) { -            super.dismissChild(view, velocity, useAccelerateInterpolator); -            if (mIsExpanded) { -                // We don't want to quick-dismiss when it's a heads up as this might lead to closing -                // of the panel early. -                handleChildViewDismissed(view); -            } -            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */, -                    false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, -                    false /* resetMenu */); -            handleMenuCoveredOrDismissed(); -        } - -        @Override -        public void snapChild(final View animView, final float targetLeft, float velocity) { -            super.snapChild(animView, targetLeft, velocity); -            onDragCancelled(animView); -            if (targetLeft == 0) { -                handleMenuCoveredOrDismissed(); -            } -        } - -        @Override -        public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) { -            mStatusBar.setNotificationSnoozed(sbn, snoozeOption); -        } - -        private void handleMenuCoveredOrDismissed() { -            if (mMenuExposedView != null && mMenuExposedView == mTranslatingParentView) { -                mMenuExposedView = null; -            } -        } - -        @Override -        public Animator getViewTranslationAnimator(View v, float target, -                AnimatorUpdateListener listener) { -            if (v instanceof ExpandableNotificationRow) { -                return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener); -            } else { -                return super.getViewTranslationAnimator(v, target, listener); -            } -        } - -        @Override -        public void setTranslation(View v, float translate) { -            ((ExpandableView) v).setTranslation(translate); -        } - -        @Override -        public float getTranslation(View v) { -            return ((ExpandableView) v).getTranslation(); -        } - -        @Override -        public void dismiss(View animView, float velocity) { -            dismissChild(animView, velocity, -                    !swipedFastEnough(0, 0) /* useAccelerateInterpolator */); -        } - -        @Override -        public void snapOpen(View animView, int targetLeft, float velocity) { -            snapChild(animView, targetLeft, velocity); -        } - -        private void snapBack(View animView, float velocity) { -            snapChild(animView, 0, velocity); -        } - -        @Override -        public boolean swipedFastEnough(float translation, float velocity) { -            return swipedFastEnough(); -        } - -        @Override -        public float getMinDismissVelocity() { -            return getEscapeVelocity(); -        } - -        public void onMenuShown(View animView) { -            onDragCancelled(animView); - -            // If we're on the lockscreen we want to false this. -            if (isAntiFalsingNeeded()) { -                mHandler.removeCallbacks(mFalsingCheck); -                mHandler.postDelayed(mFalsingCheck, COVER_MENU_DELAY); -            } -        } - -        public void closeControlsIfOutsideTouch(MotionEvent ev) { -            NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts(); -            View view = null; -            if (guts != null && !guts.getGutsContent().isLeavebehind()) { -                // Only close visible guts if they're not a leavebehind. -                view = guts; -            } else if (mCurrMenuRow != null && mCurrMenuRow.isMenuVisible() -                    && mTranslatingParentView != null) { -                // Checking menu -                view = mTranslatingParentView; -            } -            if (view != null && !isTouchInView(ev, view)) { -                // Touch was outside visible guts / menu notification, close what's visible -                mStatusBar.getGutsManager().closeAndSaveGuts(false /* removeLeavebehind */, -                        false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */, -                        false /* resetMenu */); -                resetExposedMenuView(true /* animate */, true /* force */); -            } -        } +    /** +     * Notifies a listener that the overscroll has changed. +     * +     * @param amount         the amount of overscroll, in pixels +     * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an +     *                       unrubberbanded motion to directly expand overscroll view (e.g +     *                       expand +     *                       QS) +     */ +    void onOverscrollTopChanged(float amount, boolean isRubberbanded); -        public void resetExposedMenuView(boolean animate, boolean force) { -            if (mMenuExposedView == null -                    || (!force && mMenuExposedView == mTranslatingParentView)) { -                // If no menu is showing or it's showing for this view we do nothing. -                return; -            } -            final View prevMenuExposedView = mMenuExposedView; -            if (animate) { -                Animator anim = getViewTranslationAnimator(prevMenuExposedView, -                        0 /* leftTarget */, null /* updateListener */); -                if (anim != null) { -                    anim.start(); -                } -            } else if (mMenuExposedView instanceof ExpandableNotificationRow) { -                ExpandableNotificationRow row = (ExpandableNotificationRow) mMenuExposedView; -                if (!row.isRemoved()) { -                    row.resetTranslation(); -                } -            } -            mMenuExposedView = null; -        } -    } +    /** +     * Notify a listener that the scroller wants to escape from the scrolling motion and +     * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS) +     * +     * @param velocity The velocity that the Scroller had when over flinging +     * @param open     Should the fling open or close the overscroll view. +     */ +    void flingTopOverscroll(float velocity, boolean open); +  } -  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) -  public boolean hasActiveNotifications() { +    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +    public boolean hasActiveNotifications() {          return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();      } @@ -5656,8 +5195,8 @@ public class NotificationStackScrollLayout extends ViewGroup          return mStatusBarState == StatusBarState.KEYGUARD;      } -  @ShadeViewRefactor(RefactorComponent.INPUT) -  public void updateSpeedBumpIndex() { +    @ShadeViewRefactor(RefactorComponent.INPUT) +    public void updateSpeedBumpIndex() {          int speedBumpIndex = 0;          int currentIndex = 0;          final int N = getChildCount(); @@ -5677,24 +5216,6 @@ public class NotificationStackScrollLayout extends ViewGroup          updateSpeedBumpIndex(speedBumpIndex, noAmbient);      } -    @ShadeViewRefactor(RefactorComponent.INPUT) -    private boolean isTouchInView(MotionEvent ev, View view) { -        if (view == null) { -            return false; -        } -        final int height = (view instanceof ExpandableView) -                ? ((ExpandableView) view).getActualHeight() -                : view.getHeight(); -        final int rx = (int) ev.getRawX(); -        final int ry = (int) ev.getRawY(); -        view.getLocationOnScreen(mTempInt2); -        final int x = mTempInt2[0]; -        final int y = mTempInt2[1]; -        Rect rect = new Rect(x, y, x + view.getWidth(), y + height); -        boolean ret = rect.contains(rx, ry); -        return ret; -    } -      @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)      private void updateContinuousShadowDrawing() {          boolean continuousShadowUpdate = mAnimationRunning @@ -5718,11 +5239,29 @@ public class NotificationStackScrollLayout extends ViewGroup      @ShadeViewRefactor(RefactorComponent.INPUT)      public void closeControlsIfOutsideTouch(MotionEvent ev) { -        mSwipeHelper.closeControlsIfOutsideTouch(ev); +        NotificationGuts guts = mNotificationGutsManager.getExposedGuts(); +        NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow(); +        View translatingParentView = mSwipeHelper.getTranslatingParentView(); +        View view = null; +        if (guts != null && !guts.getGutsContent().isLeavebehind()) { +            // Only close visible guts if they're not a leavebehind. +            view = guts; +        } else if (menuRow != null && menuRow.isMenuVisible() +                && translatingParentView != null) { +            // Checking menu +            view = translatingParentView; +        } +        if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) { +            // Touch was outside visible guts / menu notification, close what's visible +            mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */, +                    false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */, +                    false /* resetMenu */); +            resetExposedMenuView(true /* animate */, true /* force */); +        }      } -  @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) -  static class AnimationEvent { +    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) +    static class AnimationEvent {          static AnimationFilter[] FILTERS = new AnimationFilter[]{ @@ -6022,8 +5561,8 @@ public class NotificationStackScrollLayout extends ViewGroup          }      } -  @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) -  private final StateListener mStateListener = new StateListener() { +    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) +    private final StateListener mStateListener = new StateListener() {          @Override          public void onStatePreChange(int oldState, int newState) {              if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) { @@ -6036,9 +5575,222 @@ public class NotificationStackScrollLayout extends ViewGroup              setStatusBarState(newState);          } -      @Override -      public void onStatePostChange() { +        @Override +        public void onStatePostChange() {            NotificationStackScrollLayout.this.onStatePostChange();        } -  }; +    }; + +    class NotificationMenuListener implements NotificationMenuRowPlugin.OnMenuEventListener { +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public void onMenuClicked(View view, int x, int y, MenuItem item) { +            if (mLongPressListener == null) { +                return; +            } +            if (view instanceof ExpandableNotificationRow) { +                ExpandableNotificationRow row = (ExpandableNotificationRow) view; +                MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR, +                        row.getStatusBarNotification().getPackageName()); +            } +            mLongPressListener.onLongPress(view, x, y, item); +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public void onMenuReset(View row) { +            View translatingParentView = mSwipeHelper.getTranslatingParentView(); +            if (translatingParentView != null && row == translatingParentView) { +                mSwipeHelper.clearExposedMenuView(); +                mSwipeHelper.clearTranslatingParentView(); +            } +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public void onMenuShown(View row) { +            if (row instanceof ExpandableNotificationRow) { +                MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR, +                        ((ExpandableNotificationRow) row).getStatusBarNotification() +                                .getPackageName()); +            } +            mSwipeHelper.onMenuShown(row); +        } +    } + +    class SwipeHelperCallback implements NotificationSwipeHelper.NotificationCallback { +        @Override +        public void onDismiss() { +            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, +                    false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, +                    false /* resetMenu */); +        } + +        @Override +        public void onSnooze(StatusBarNotification sbn, +                NotificationSwipeActionHelper.SnoozeOption snoozeOption) { +            mStatusBar.setNotificationSnoozed(sbn, snoozeOption); +        } + +        @Override +        public boolean isExpanded() { +            return NotificationStackScrollLayout.this.isExpanded(); +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public void onDragCancelled(View v) { +            mFalsingManager.onNotificatonStopDismissing(); +            setSwipingInProgress(false); +        } + +        /** +         * Handles cleanup after the given {@code view} has been fully swiped out (including +         * re-invoking dismiss logic in case the notification has not made its way out yet). +         */ +        @Override +        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +        public void onChildDismissed(View view) { +            ExpandableNotificationRow row = (ExpandableNotificationRow) view; +            if (!row.isDismissed()) { +                handleChildViewDismissed(view); +            } +            ViewGroup transientContainer = row.getTransientContainer(); +            if (transientContainer != null) { +                transientContainer.removeTransientView(view); +            } +        } + +        /** +         * Starts up notification dismiss and tells the notification, if any, to remove itself from +         * layout. +         * +         * @param view view (e.g. notification) to dismiss from the layout +         */ + +        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +        public void handleChildViewDismissed(View view) { +            if (mDismissAllInProgress) { +                return; +            } + +            boolean isBlockingHelperShown = false; + +            setSwipingInProgress(false); +            if (mDragAnimPendingChildren.contains(view)) { +                // We start the swipe and finish it in the same frame; we don't want a drag +                // animation. +                mDragAnimPendingChildren.remove(view); +            } +            mAmbientState.onDragFinished(view); +            updateContinuousShadowDrawing(); + +            if (view instanceof ExpandableNotificationRow) { +                ExpandableNotificationRow row = (ExpandableNotificationRow) view; +                if (row.isHeadsUp()) { +                    mHeadsUpManager.addSwipedOutNotification( +                            row.getStatusBarNotification().getKey()); +                } +                isBlockingHelperShown = +                        row.performDismissWithBlockingHelper(false /* fromAccessibility */); +            } + +            if (!isBlockingHelperShown) { +                mSwipedOutViews.add(view); +            } +            mFalsingManager.onNotificationDismissed(); +            if (mFalsingManager.shouldEnforceBouncer()) { +                mStatusBar.executeRunnableDismissingKeyguard( +                        null, +                        null /* cancelAction */, +                        false /* dismissShade */, +                        true /* afterKeyguardGone */, +                        false /* deferred */); +            } +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public boolean isAntiFalsingNeeded() { +            return onKeyguard(); +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public View getChildAtPosition(MotionEvent ev) { +            View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(), +                    ev.getY()); +            if (child instanceof ExpandableNotificationRow) { +                ExpandableNotificationRow row = (ExpandableNotificationRow) child; +                ExpandableNotificationRow parent = row.getNotificationParent(); +                if (parent != null && parent.areChildrenExpanded() +                        && (parent.areGutsExposed() +                        || mSwipeHelper.getExposedMenuView() == parent +                        || (parent.getNotificationChildren().size() == 1 +                        && parent.isClearable()))) { +                    // In this case the group is expanded and showing the menu for the +                    // group, further interaction should apply to the group, not any +                    // child notifications so we use the parent of the child. We also do the same +                    // if we only have a single child. +                    child = parent; +                } +            } +            return child; +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public void onBeginDrag(View v) { +            mFalsingManager.onNotificatonStartDismissing(); +            setSwipingInProgress(true); +            mAmbientState.onBeginDrag(v); +            updateContinuousShadowDrawing(); +            if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) { +                mDragAnimPendingChildren.add(v); +                mNeedsAnimation = true; +            } +            requestChildrenUpdate(); +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) +        public void onChildSnappedBack(View animView, float targetLeft) { +            mAmbientState.onDragFinished(animView); +            updateContinuousShadowDrawing(); +            if (!mDragAnimPendingChildren.contains(animView)) { +                if (mAnimationsEnabled) { +                    mSnappedBackChildren.add(animView); +                    mNeedsAnimation = true; +                } +                requestChildrenUpdate(); +            } else { +                // We start the swipe and snap back in the same frame, we don't want any animation +                mDragAnimPendingChildren.remove(animView); +            } +            NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow(); +            if (menuRow != null && targetLeft == 0) { +                menuRow.resetMenu(); +                mSwipeHelper.clearCurrentMenuRow(); +            } +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public boolean updateSwipeProgress(View animView, boolean dismissable, +                float swipeProgress) { +            // Returning true prevents alpha fading. +            return !mFadeNotificationsOnDismiss; +        } + +        @Override +        @ShadeViewRefactor(RefactorComponent.INPUT) +        public float getFalsingThresholdFactor() { +            return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f; +        } + +        @Override +        public boolean canChildBeDismissed(View v) { +            return NotificationStackScrollLayout.this.canChildBeDismissed(v); +        } +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java new file mode 100644 index 000000000000..028957d233ff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -0,0 +1,424 @@ +/* + * 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 Licen + */ + + +package com.android.systemui.statusbar.notification.stack; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Rect; +import android.os.Handler; +import android.service.notification.StatusBarNotification; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.SwipeHelper; +import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.statusbar.notification.ShadeViewRefactor; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; + +@ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.INPUT) +class NotificationSwipeHelper extends SwipeHelper +        implements NotificationSwipeActionHelper { +    @VisibleForTesting +    protected static final long COVER_MENU_DELAY = 4000; +    private static final String TAG = "NotificationSwipeHelper"; +    private final Runnable mFalsingCheck; +    private View mTranslatingParentView; +    private View mMenuExposedView; +    private final NotificationCallback mCallback; +    private final NotificationMenuRowPlugin.OnMenuEventListener mMenuListener; + +    private static final long SWIPE_MENU_TIMING = 200; + +    private NotificationMenuRowPlugin mCurrMenuRow; + +    public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback, +            Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) { +        super(swipeDirection, callback, context); +        mMenuListener = menuListener; +        mCallback = callback; +        mFalsingCheck = new Runnable() { +            @Override +            public void run() { +                resetExposedMenuView(true /* animate */, true /* force */); +            } +        }; +    } + +    public View getTranslatingParentView() { +        return mTranslatingParentView; +    } + +    public void clearTranslatingParentView() { setTranslatingParentView(null); } + +    @VisibleForTesting +    protected void setTranslatingParentView(View view) { mTranslatingParentView = view; }; + +    public void setExposedMenuView(View view) { +        mMenuExposedView = view; +    } + +    public void clearExposedMenuView() { setExposedMenuView(null); } + +    public void clearCurrentMenuRow() { setCurrentMenuRow(null); } + +    public View getExposedMenuView() { +        return mMenuExposedView; +    } + +    public void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) { +        mCurrMenuRow = menuRow; +    } + +    public NotificationMenuRowPlugin getCurrentMenuRow() {  return mCurrMenuRow; } + +    @VisibleForTesting +    protected Handler getHandler() { return mHandler; } + +    @VisibleForTesting +    protected Runnable getFalsingCheck() { return mFalsingCheck; }; + +    @Override +    public void onDownUpdate(View currView, MotionEvent ev) { +        mTranslatingParentView = currView; +        NotificationMenuRowPlugin menuRow = getCurrentMenuRow(); +        if (menuRow != null) { +            menuRow.onTouchStart(); +        } +        clearCurrentMenuRow(); +        getHandler().removeCallbacks(getFalsingCheck()); + +        // Slide back any notifications that might be showing a menu +        resetExposedMenuView(true /* animate */, false /* force */); + +        if (currView instanceof ExpandableNotificationRow) { +            initializeRow((ExpandableNotificationRow) currView); +        } +    } + +    @VisibleForTesting +    protected void initializeRow(ExpandableNotificationRow row) { +        if (row.getEntry().hasFinishedInitialization()) { +            mCurrMenuRow = row.createMenu(); +            mCurrMenuRow.setMenuClickListener(mMenuListener); +            mCurrMenuRow.onTouchStart(); +        } +    } + +    private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) { +        return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu(); +    } + +    @Override +    public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) { +        getHandler().removeCallbacks(getFalsingCheck()); +        NotificationMenuRowPlugin menuRow = getCurrentMenuRow(); +        if (menuRow != null) { +            menuRow.onTouchMove(delta); +        } +    } + +    @Override +    public boolean handleUpEvent(MotionEvent ev, View animView, float velocity, +            float translation) { +        NotificationMenuRowPlugin menuRow = getCurrentMenuRow(); +        if (menuRow != null) { +            menuRow.onTouchEnd(); +            handleMenuRowSwipe(ev, animView, velocity, menuRow); +            return true; +        } +        return false; +    } + +    @VisibleForTesting +    protected void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity, +            NotificationMenuRowPlugin menuRow) { +        if (!menuRow.shouldShowMenu()) { +            // If the menu should not be shown, then there is no need to check if the a swipe +            // should result in a snapping to the menu. As a result, just check if the swipe +            // was enough to dismiss the notification. +            if (isDismissGesture(ev)) { +                dismiss(animView, velocity); +            } else { +                snapClosed(animView, velocity); +                menuRow.onSnapClosed(); +            } +            return; +        } + +        if (menuRow.isSnappedAndOnSameSide()) { +            // Menu was snapped to previously and we're on the same side +            handleSwipeFromSnap(ev, animView, velocity, menuRow); +        } else { +            // Menu has not been snapped, or was snapped previously but is now on +            // the opposite side. +            handleSwipeFromNonSnap(ev, animView, velocity, menuRow); +        } +    } + +    private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity, +            NotificationMenuRowPlugin menuRow) { +        boolean isDismissGesture = isDismissGesture(ev); +        final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity); +        final boolean gestureFastEnough = getEscapeVelocity() <= Math.abs(velocity); + +        final double timeForGesture = ev.getEventTime() - ev.getDownTime(); +        final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed() +                && timeForGesture >= SWIPE_MENU_TIMING; + +        if (!isFalseGesture(ev) +                && (swipedEnoughToShowMenu(menuRow) +                && (!gestureFastEnough || showMenuForSlowOnGoing)) +                || (gestureTowardsMenu && !isDismissGesture)) { +            // Menu has not been snapped to previously and this is menu revealing gesture +            snapOpen(animView, menuRow.getMenuSnapTarget(), velocity); +            menuRow.onSnapOpen(); +        } else if (isDismissGesture(ev) && !gestureTowardsMenu) { +            dismiss(animView, velocity); +            menuRow.onDismiss(); +        } else { +            snapClosed(animView, velocity); +            menuRow.onSnapClosed(); +        } +    } + +    private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity, +            NotificationMenuRowPlugin menuRow) { +        boolean isDismissGesture = isDismissGesture(ev); + +        final boolean withinSnapMenuThreshold = +                menuRow.isWithinSnapMenuThreshold(); + +        if (withinSnapMenuThreshold && !isDismissGesture) { +            // Haven't moved enough to unsnap from the menu +            menuRow.onSnapOpen(); +            snapOpen(animView, menuRow.getMenuSnapTarget(), velocity); +        } else if (isDismissGesture && !menuRow.shouldSnapBack()) { +            // Only dismiss if we're not moving towards the menu +            dismiss(animView, velocity); +            menuRow.onDismiss(); +        } else { +            snapClosed(animView, velocity); +            menuRow.onSnapClosed(); +        } +    } + +    @Override +    public void dismissChild(final View view, float velocity, +            boolean useAccelerateInterpolator) { +        superDismissChild(view, velocity, useAccelerateInterpolator); +        if (mCallback.isExpanded()) { +            // We don't want to quick-dismiss when it's a heads up as this might lead to closing +            // of the panel early. +            mCallback.handleChildViewDismissed(view); +        } +        mCallback.onDismiss(); +        handleMenuCoveredOrDismissed(); +    } + +    @VisibleForTesting +    protected void superDismissChild(final View view, float velocity, boolean useAccelerateInterpolator) { +        super.dismissChild(view, velocity, useAccelerateInterpolator); +    } + +    @VisibleForTesting +    protected void superSnapChild(final View animView, final float targetLeft, float velocity) { +        super.snapChild(animView, targetLeft, velocity); +    } + +    @Override +    public void snapChild(final View animView, final float targetLeft, float velocity) { +        superSnapChild(animView, targetLeft, velocity); +        mCallback.onDragCancelled(animView); +        if (targetLeft == 0) { +            handleMenuCoveredOrDismissed(); +        } +    } + +    @Override +    public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) { +        mCallback.onSnooze(sbn, snoozeOption); +    } + +    @VisibleForTesting +    protected void handleMenuCoveredOrDismissed() { +        View exposedMenuView = getExposedMenuView(); +        if (exposedMenuView != null && exposedMenuView == mTranslatingParentView) { +            clearExposedMenuView(); +        } +    } + +    @VisibleForTesting +    protected Animator superGetViewTranslationAnimator(View v, float target, +            ValueAnimator.AnimatorUpdateListener listener) { +        return super.getViewTranslationAnimator(v, target, listener); +    } + +    @Override +    public Animator getViewTranslationAnimator(View v, float target, +            ValueAnimator.AnimatorUpdateListener listener) { +        if (v instanceof ExpandableNotificationRow) { +            return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener); +        } else { +            return superGetViewTranslationAnimator(v, target, listener); +        } +    } + +    @Override +    public void setTranslation(View v, float translate) { +        if (v instanceof ExpandableNotificationRow) { +            ((ExpandableNotificationRow) v).setTranslation(translate); +        } else { +            Log.wtf(TAG, "setTranslation should only be called on an ExpandableNotificationRow."); +        } +    } + +    @Override +    public float getTranslation(View v) { +        if (v instanceof ExpandableNotificationRow) { +            return ((ExpandableNotificationRow) v).getTranslation(); +        } +        else { +            Log.wtf(TAG, "getTranslation should only be called on an ExpandableNotificationRow."); +            return 0f; +        } +    } + +    @Override +    public boolean swipedFastEnough(float translation, float viewSize) { +        return swipedFastEnough(); +    } + +    @Override +    @VisibleForTesting +    protected boolean swipedFastEnough() { +        return super.swipedFastEnough(); +    } + +    @Override +    public boolean swipedFarEnough(float translation, float viewSize) { +        return swipedFarEnough(); +    } + +    @Override +    @VisibleForTesting +    protected boolean swipedFarEnough() { +        return super.swipedFarEnough(); +    } + +    @Override +    public void dismiss(View animView, float velocity) { +        dismissChild(animView, velocity, +                !swipedFastEnough() /* useAccelerateInterpolator */); +    } + +    @Override +    public void snapOpen(View animView, int targetLeft, float velocity) { +        snapChild(animView, targetLeft, velocity); +    } + +    @VisibleForTesting +    protected void snapClosed(View animView, float velocity) { +        snapChild(animView, 0, velocity); +    } + +    @Override +    @VisibleForTesting +    protected float getEscapeVelocity() { +        return super.getEscapeVelocity(); +    } + +    @Override +    public float getMinDismissVelocity() { +        return getEscapeVelocity(); +    } + +    public void onMenuShown(View animView) { +        setExposedMenuView(getTranslatingParentView()); +        mCallback.onDragCancelled(animView); +        Handler handler = getHandler(); + +        // If we're on the lockscreen we want to false this. +        if (mCallback.isAntiFalsingNeeded()) { +            handler.removeCallbacks(getFalsingCheck()); +            handler.postDelayed(getFalsingCheck(), COVER_MENU_DELAY); +        } +    } + +    @VisibleForTesting +    protected boolean shouldResetMenu(boolean force) { +        if (mMenuExposedView == null +                || (!force && mMenuExposedView == mTranslatingParentView)) { +            // If no menu is showing or it's showing for this view we do nothing. +            return false; +        } +        return true; +    } + +    public void resetExposedMenuView(boolean animate, boolean force) { +        if (!shouldResetMenu(force)) { +            return; +        } +        final View prevMenuExposedView = getExposedMenuView(); +        if (animate) { +            Animator anim = getViewTranslationAnimator(prevMenuExposedView, +                    0 /* leftTarget */, null /* updateListener */); +            if (anim != null) { +                anim.start(); +            } +        } else if (prevMenuExposedView instanceof ExpandableNotificationRow) { +            ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView; +            if (!row.isRemoved()) { +                row.resetTranslation(); +            } +        } +        clearExposedMenuView(); +    } + +    public static boolean isTouchInView(MotionEvent ev, View view) { +        if (view == null) { +            return false; +        } +        final int height = (view instanceof ExpandableView) +                ? ((ExpandableView) view).getActualHeight() +                : view.getHeight(); +        final int rx = (int) ev.getRawX(); +        final int ry = (int) ev.getRawY(); +        int[] temp = new int[2]; +        view.getLocationOnScreen(temp); +        final int x = temp[0]; +        final int y = temp[1]; +        Rect rect = new Rect(x, y, x + view.getWidth(), y + height); +        boolean ret = rect.contains(rx, ry); +        return ret; +    } + +    public interface NotificationCallback extends SwipeHelper.Callback{ +        boolean isExpanded(); + +        void handleChildViewDismissed(View view); + +        void onSnooze(StatusBarNotification sbn, SnoozeOption snoozeOption); + +        void onDismiss(); +    } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java index 4f957bfcbbcc..c7ab27ba715d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java @@ -67,9 +67,15 @@ public class ContextualButton extends ButtonDispatcher {      }      protected KeyButtonDrawable getNewDrawable() { -        return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */); +        return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId, +                false /* shadow */);      } +    /** +     * This context is from the view that could be stale after rotation or config change. To get +     * correct resources use getApplicationContext() as well. +     * @return current view context +     */      protected Context getContext() {          return getCurrentView().getContext();      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index cbbb0e3dea96..9c579daa38c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -35,6 +35,7 @@ import android.animation.AnimatorListenerAdapter;  import android.animation.ObjectAnimator;  import android.annotation.IdRes;  import android.annotation.Nullable; +import android.app.ActivityManager;  import android.app.ActivityTaskManager;  import android.app.Fragment;  import android.app.IActivityManager; @@ -88,8 +89,8 @@ import com.android.systemui.assist.AssistManager;  import com.android.systemui.fragments.FragmentHostManager;  import com.android.systemui.fragments.FragmentHostManager.FragmentListener;  import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener;  import com.android.systemui.stackdivider.Divider;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.CommandQueue.Callbacks; @@ -284,7 +285,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {          mNavigationBarView = (NavigationBarView) view;          mNavigationBarView.setDisabledFlags(mDisabledFlags1); -        mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel()); +        mNavigationBarView.setComponents(mStatusBar.getPanel());          mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);          mNavigationBarView.setOnTouchListener(this::onNavigationTouch);          if (savedInstanceState != null) { @@ -946,7 +947,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {      private boolean onLongPressRecents() {          if (mRecents == null || !ActivityTaskManager.supportsMultiWindow(getContext())                  || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible() -                || Recents.getConfiguration().isLowRamDevice +                || ActivityManager.isLowRamDeviceStatic()                  // If we are connected to the overview service, then disable the recents button                  || mOverviewProxyService.getProxy() != null) {              return false; @@ -1110,7 +1111,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {          }      }; -    class TaskStackListenerImpl extends SysUiTaskStackChangeListener { +    class TaskStackListenerImpl extends TaskStackChangeListener {          // Invalidate any rotation suggestion on task change or activity orientation change          // Note: all callbacks happen on main thread diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java deleted file mode 100644 index 8c02e1f8220b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_TOP; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.RecentsComponent; -import com.android.systemui.SysUiServiceProvider; -import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.tuner.TunerService; - -/** - * Class to detect gestures on the navigation bar. - */ -public class NavigationBarGestureHelper implements TunerService.Tunable, GestureHelper { - -    private static final String TAG = "NavBarGestureHelper"; -    private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture"; -    /** -     * When dragging from the navigation bar, we drag in recents. -     */ -    public static final int DRAG_MODE_NONE = -1; - -    /** -     * When dragging from the navigation bar, we drag in recents. -     */ -    public static final int DRAG_MODE_RECENTS = 0; - -    /** -     * When dragging from the navigation bar, we drag the divider. -     */ -    public static final int DRAG_MODE_DIVIDER = 1; - -    private RecentsComponent mRecentsComponent; -    private Divider mDivider; -    private Context mContext; -    private NavigationBarView mNavigationBarView; -    private boolean mIsVertical; - -    private final QuickStepController mQuickStepController; -    private final int mScrollTouchSlop; -    private final StatusBar mStatusBar; -    private int mTouchDownX; -    private int mTouchDownY; -    private boolean mDownOnRecents; -    private VelocityTracker mVelocityTracker; - -    private boolean mDockWindowEnabled; -    private boolean mDockWindowTouchSlopExceeded; -    private int mDragMode; - -    public NavigationBarGestureHelper(Context context) { -        mContext = context; -        mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class); -        Resources r = context.getResources(); -        mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance); -        mQuickStepController = new QuickStepController(context); -        Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE); -    } - -    public void destroy() { -        Dependency.get(TunerService.class).removeTunable(this); -    } - -    public void setComponents(RecentsComponent recentsComponent, Divider divider, -            NavigationBarView navigationBarView) { -        mRecentsComponent = recentsComponent; -        mDivider = divider; -        mNavigationBarView = navigationBarView; -        mQuickStepController.setComponents(mNavigationBarView); -    } - -    public void setBarState(boolean isVertical, boolean isRTL) { -        mIsVertical = isVertical; -        mQuickStepController.setBarState(isVertical, isRTL); -    } - -    public boolean onInterceptTouchEvent(MotionEvent event) { -        if (!canHandleGestures()) { -            return false; -        } -        boolean result = mQuickStepController.onInterceptTouchEvent(event); -        if (mDockWindowEnabled) { -            result |= interceptDockWindowEvent(event); -        } -        return result; -    } - -    public boolean onTouchEvent(MotionEvent event) { -        if (!canHandleGestures()) { -            return false; -        } -        boolean result = mQuickStepController.onTouchEvent(event); -        if (mDockWindowEnabled) { -            result |= handleDockWindowEvent(event); -        } -        return result; -    } - -    public void onDraw(Canvas canvas) { -        mQuickStepController.onDraw(canvas); -    } - -    public void onLayout(boolean changed, int left, int top, int right, int bottom) { -        mQuickStepController.onLayout(changed, left, top, right, bottom); -    } - -    public void onDarkIntensityChange(float intensity) { -        mQuickStepController.onDarkIntensityChange(intensity); -    } - -    public void onNavigationButtonLongPress(View v) { -        mQuickStepController.onNavigationButtonLongPress(v); -    } - -    private boolean interceptDockWindowEvent(MotionEvent event) { -        switch (event.getActionMasked()) { -            case MotionEvent.ACTION_DOWN: -                handleDragActionDownEvent(event); -                break; -            case MotionEvent.ACTION_MOVE: -                return handleDragActionMoveEvent(event); -            case MotionEvent.ACTION_UP: -            case MotionEvent.ACTION_CANCEL: -                handleDragActionUpEvent(event); -                break; -        } -        return false; -    } - -    private boolean handleDockWindowEvent(MotionEvent event) { -        switch (event.getActionMasked()) { -            case MotionEvent.ACTION_DOWN: -                handleDragActionDownEvent(event); -                break; -            case MotionEvent.ACTION_MOVE: -                handleDragActionMoveEvent(event); -                break; -            case MotionEvent.ACTION_UP: -            case MotionEvent.ACTION_CANCEL: -                handleDragActionUpEvent(event); -                break; -        } -        return true; -    } - -    private void handleDragActionDownEvent(MotionEvent event) { -        mVelocityTracker = VelocityTracker.obtain(); -        mVelocityTracker.addMovement(event); -        mDockWindowTouchSlopExceeded = false; -        mTouchDownX = (int) event.getX(); -        mTouchDownY = (int) event.getY(); - -        if (mNavigationBarView != null) { -            View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView(); -            if (recentsButton != null) { -                mDownOnRecents = mTouchDownX >= recentsButton.getLeft() -                        && mTouchDownX <= recentsButton.getRight() -                        && mTouchDownY >= recentsButton.getTop() -                        && mTouchDownY <= recentsButton.getBottom(); -            } else { -                mDownOnRecents = false; -            } -        } -    } - -    private boolean handleDragActionMoveEvent(MotionEvent event) { -        mVelocityTracker.addMovement(event); -        int x = (int) event.getX(); -        int y = (int) event.getY(); -        int xDiff = Math.abs(x - mTouchDownX); -        int yDiff = Math.abs(y - mTouchDownY); -        if (mDivider == null || mRecentsComponent == null) { -            return false; -        } -        if (!mDockWindowTouchSlopExceeded) { -            boolean touchSlopExceeded = !mIsVertical -                    ? yDiff > mScrollTouchSlop && yDiff > xDiff -                    : xDiff > mScrollTouchSlop && xDiff > yDiff; -            if (mDownOnRecents && touchSlopExceeded -                    && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) { -                Rect initialBounds = null; -                int dragMode = calculateDragMode(); -                int createMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -                if (dragMode == DRAG_MODE_DIVIDER) { -                    initialBounds = new Rect(); -                    mDivider.getView().calculateBoundsForPosition(mIsVertical -                                    ? (int) event.getRawX() -                                    : (int) event.getRawY(), -                            mDivider.getView().isHorizontalDivision() -                                    ? DOCKED_TOP -                                    : DOCKED_LEFT, -                            initialBounds); -                } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX -                        < mContext.getResources().getDisplayMetrics().widthPixels / 2) { -                    createMode = SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; -                } -                boolean docked = mRecentsComponent.splitPrimaryTask(dragMode, createMode, -                        initialBounds, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE); -                if (docked) { -                    mDragMode = dragMode; -                    if (mDragMode == DRAG_MODE_DIVIDER) { -                        mDivider.getView().startDragging(false /* animate */, true /* touching*/); -                    } -                    mDockWindowTouchSlopExceeded = true; -                    return true; -                } -            } -        } else { -            if (mDragMode == DRAG_MODE_DIVIDER) { -                int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX(); -                SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm() -                        .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */); -                mDivider.getView().resizeStack(position, snapTarget.position, snapTarget); -            } else if (mDragMode == DRAG_MODE_RECENTS) { -                mRecentsComponent.onDraggingInRecents(event.getRawY()); -            } -        } -        return false; -    } - -    private void handleDragActionUpEvent(MotionEvent event) { -        mVelocityTracker.addMovement(event); -        mVelocityTracker.computeCurrentVelocity(1000); -        if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) { -            if (mDragMode == DRAG_MODE_DIVIDER) { -                mDivider.getView().stopDragging(mIsVertical -                                ? (int) event.getRawX() -                                : (int) event.getRawY(), -                        mIsVertical -                                ? mVelocityTracker.getXVelocity() -                                : mVelocityTracker.getYVelocity(), -                        true /* avoidDismissStart */, false /* logMetrics */); -            } else if (mDragMode == DRAG_MODE_RECENTS) { -                mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity()); -            } -        } -        mVelocityTracker.recycle(); -        mVelocityTracker = null; -    } - -    private boolean canHandleGestures() { -        return !mStatusBar.isKeyguardShowing(); -    } - -    private int calculateDragMode() { -        if (mIsVertical && !mDivider.getView().isHorizontalDivision()) { -            return DRAG_MODE_DIVIDER; -        } -        if (!mIsVertical && mDivider.getView().isHorizontalDivision()) { -            return DRAG_MODE_DIVIDER; -        } -        return DRAG_MODE_RECENTS; -    } - -    @Override -    public void onTuningChanged(String key, String newValue) { -        switch (key) { -            case KEY_DOCK_WINDOW_GESTURE: -                mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0); -                break; -        } -    } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java index e6f2c33c33d2..52134d9d713c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -37,7 +37,7 @@ import com.android.systemui.Dependency;  import com.android.systemui.OverviewProxyService;  import com.android.systemui.R;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider;  import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;  import com.android.systemui.statusbar.policy.KeyButtonView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 71b35e043f77..16b2987558d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -40,7 +40,6 @@ import android.os.Bundle;  import android.os.Handler;  import android.os.Message;  import android.os.SystemProperties; -import androidx.annotation.ColorInt;  import android.util.AttributeSet;  import android.util.Log;  import android.util.SparseArray; @@ -64,12 +63,11 @@ import com.android.systemui.R;  import com.android.systemui.RecentsComponent;  import com.android.systemui.SysUiServiceProvider;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.plugins.statusbar.phone.NavGesture;  import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;  import com.android.systemui.recents.Recents;  import com.android.systemui.recents.RecentsOnboarding; -import com.android.systemui.shared.recents.IOverviewProxy;  import com.android.systemui.shared.system.ActivityManagerWrapper;  import com.android.systemui.shared.system.NavigationBarCompat;  import com.android.systemui.shared.system.WindowManagerWrapper; @@ -144,8 +142,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav      private Configuration mConfiguration;      private NavigationBarInflaterView mNavigationInflaterView; -    private RecentsComponent mRecentsComponent; -    private Divider mDivider;      private RecentsOnboarding mRecentsOnboarding;      private NotificationPanelView mPanelView; @@ -314,14 +310,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav          return mBarTransitions.getLightTransitionsController();      } -    public void setComponents(RecentsComponent recentsComponent, Divider divider, -            NotificationPanelView panel) { -        mRecentsComponent = recentsComponent; -        mDivider = divider; +    public void setComponents(NotificationPanelView panel) {          mPanelView = panel; -        if (mGestureHelper instanceof NavigationBarGestureHelper) { -            ((NavigationBarGestureHelper) mGestureHelper).setComponents( -                    recentsComponent, divider, this); +        if (mGestureHelper instanceof QuickStepController) { +            ((QuickStepController) mGestureHelper).setComponents(this);          }      } @@ -1077,8 +1069,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav      @Override      public void onPluginDisconnected(NavGesture plugin) { -        NavigationBarGestureHelper defaultHelper = new NavigationBarGestureHelper(getContext()); -        defaultHelper.setComponents(mRecentsComponent, mDivider, this); +        QuickStepController defaultHelper = new QuickStepController(getContext()); +        defaultHelper.setComponents(this);          if (mGestureHelper != null) {              mGestureHelper.destroy();          } @@ -1123,6 +1115,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav          pw.println("    }");          mContextualButtonGroup.dump(pw); +        mGestureHelper.dump(pw);          mRecentsOnboarding.dump(pw);      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java index 9ff907b17564..9e561d13f347 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java @@ -24,7 +24,7 @@ import com.android.systemui.Dependency;  import com.android.systemui.plugins.NotificationListenerController;  import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 1afdc66b9227..553165b40153 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -67,8 +67,8 @@ import com.android.systemui.SysUiServiceProvider;  import com.android.systemui.UiOffloadThread;  import com.android.systemui.qs.tiles.DndTile;  import com.android.systemui.qs.tiles.RotationLockTile; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener;  import com.android.systemui.statusbar.CommandQueue;  import com.android.systemui.statusbar.CommandQueue.Callbacks;  import com.android.systemui.statusbar.policy.BluetoothController; @@ -797,7 +797,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,          mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);      } -    private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() { +    private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {          @Override          public void onTaskStackChanged() {              // Listen for changes to stacks and then check which instant apps are foreground. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java index 30e6afa8465f..bce52a294e85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java @@ -58,10 +58,12 @@ import com.android.systemui.Dependency;  import com.android.systemui.Interpolators;  import com.android.systemui.OverviewProxyService;  import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider;  import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;  import com.android.systemui.shared.recents.IOverviewProxy;  import com.android.systemui.shared.recents.utilities.Utilities;  import com.android.systemui.shared.system.NavigationBarCompat; +import java.io.PrintWriter;  /**   * Class to detect gestures on the navigation bar and implement quick scrub. @@ -117,6 +119,7 @@ public class QuickStepController implements GestureHelper {      private final int mTrackEndPadding;      private final int mHomeBackGestureDragLimit;      private final Context mContext; +    private final StatusBar mStatusBar;      private final Matrix mTransformGlobalMatrix = new Matrix();      private final Matrix mTransformLocalMatrix = new Matrix();      private final Paint mTrackPaint = new Paint(); @@ -195,6 +198,7 @@ public class QuickStepController implements GestureHelper {      public QuickStepController(Context context) {          final Resources res = context.getResources();          mContext = context; +        mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);          mOverviewEventSender = Dependency.get(OverviewProxyService.class);          mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);          mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding); @@ -218,6 +222,10 @@ public class QuickStepController implements GestureHelper {       */      @Override      public boolean onInterceptTouchEvent(MotionEvent event) { +        if (mStatusBar.isKeyguardShowing()) { +            // Disallow any handling when the keyguard is showing +            return false; +        }          return handleTouchEvent(event);      } @@ -227,6 +235,11 @@ public class QuickStepController implements GestureHelper {       */      @Override      public boolean onTouchEvent(MotionEvent event) { +        if (mStatusBar.isKeyguardShowing()) { +            // Disallow any handling when the keyguard is showing +            return false; +        } +          // The same down event was just sent on intercept and therefore can be ignored here          final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN                  && mOverviewEventSender.getProxy() != null; @@ -483,6 +496,21 @@ public class QuickStepController implements GestureHelper {          mHandler.removeCallbacksAndMessages(null);      } +    @Override +    public void dump(PrintWriter pw) { +        pw.println("QuickStepController {"); +        pw.print("    "); pw.println("mQuickScrubActive=" + mQuickScrubActive); +        pw.print("    "); pw.println("mQuickStepStarted=" + mQuickStepStarted); +        pw.print("    "); pw.println("mAllowGestureDetection=" + mAllowGestureDetection); +        pw.print("    "); pw.println("mBackGestureActive=" + mBackGestureActive); +        pw.print("    "); pw.println("mCanPerformBack=" + mCanPerformBack); +        pw.print("    "); pw.println("mNotificationsVisibleOnDown=" + mNotificationsVisibleOnDown); +        pw.print("    "); pw.println("mIsVertical=" + mIsVertical); +        pw.print("    "); pw.println("mIsRTL=" + mIsRTL); +        pw.print("    "); pw.println("mIsInScreenPinning=" + mIsInScreenPinning); +        pw.println("}"); +    } +      private void startQuickStep(MotionEvent event) {          if (mIsInScreenPinning) {              mNavigationBarView.showPinningEscapeToast(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index ff38380b7aa8..c3b87af612cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -102,6 +102,8 @@ import android.os.UserManager;  import android.os.VibrationEffect;  import android.os.Vibrator;  import android.provider.Settings; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager;  import android.service.notification.StatusBarNotification;  import android.service.vr.IVrManager;  import android.service.vr.IVrStateCallbacks; @@ -154,6 +156,7 @@ import com.android.systemui.Interpolators;  import com.android.systemui.Prefs;  import com.android.systemui.R;  import com.android.systemui.RecentsComponent; +import com.android.systemui.SysUiServiceProvider;  import com.android.systemui.SystemUI;  import com.android.systemui.SystemUIFactory;  import com.android.systemui.UiOffloadThread; @@ -179,10 +182,6 @@ import com.android.systemui.qs.QSTileHost;  import com.android.systemui.qs.car.CarQSFragment;  import com.android.systemui.recents.Recents;  import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; -import com.android.systemui.recents.events.activity.UndockingTaskEvent; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.shared.system.WindowManagerWrapper;  import com.android.systemui.stackdivider.Divider;  import com.android.systemui.stackdivider.WindowManagerProxy; @@ -635,6 +634,8 @@ public class StatusBar extends SystemUI implements DemoMode,          mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR);          mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); +        mDreamManager = IDreamManager.Stub.asInterface( +                ServiceManager.checkService(DreamService.DREAM_SERVICE));          mDisplay = mWindowManager.getDefaultDisplay();          updateDisplaySize(); @@ -1214,17 +1215,18 @@ public class StatusBar extends SystemUI implements DemoMode,              int createMode = navbarPos == NAV_BAR_POS_LEFT                      ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT                      : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode, -                    null, metricsDockAction); +            return mRecents.splitPrimaryTask(createMode, null, metricsDockAction);          } else {              Divider divider = getComponent(Divider.class); -            if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) { -                // Undocking from the minimized state is not supported -                return false; -            } else { -                EventBus.getDefault().send(new UndockingTaskEvent()); -                if (metricsUndockAction != -1) { -                    mMetricsLogger.action(metricsUndockAction); +            if (divider != null) { +                if (divider.isMinimized() && !divider.isHomeStackResizable()) { +                    // Undocking from the minimized state is not supported +                    return false; +                } else { +                    divider.onUndockingTask(); +                    if (metricsUndockAction != -1) { +                        mMetricsLogger.action(metricsUndockAction); +                    }                  }              }          } @@ -2180,7 +2182,7 @@ public class StatusBar extends SystemUI implements DemoMode,      }      @Override -    public void animateExpandSettingsPanel(String subPanel) { +    public void animateExpandSettingsPanel(@Nullable String subPanel) {          if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);          if (!panelsEnabled()) {              return; @@ -2189,7 +2191,6 @@ public class StatusBar extends SystemUI implements DemoMode,          // Settings are not available in setup          if (!mUserSetup) return; -          if (subPanel != null) {              mQSPanel.openDetails(subPanel);          } @@ -4246,12 +4247,12 @@ public class StatusBar extends SystemUI implements DemoMode,      @Override      public void appTransitionCancelled() { -        EventBus.getDefault().send(new AppTransitionFinishedEvent()); +        getComponent(Divider.class).onAppTransitionFinished();      }      @Override      public void appTransitionFinished() { -        EventBus.getDefault().send(new AppTransitionFinishedEvent()); +        getComponent(Divider.class).onAppTransitionFinished();      }      @Override @@ -4663,6 +4664,7 @@ public class StatusBar extends SystemUI implements DemoMode,      protected WindowManager mWindowManager;      protected IWindowManager mWindowManagerService; +    private IDreamManager mDreamManager;      protected Display mDisplay; @@ -4967,7 +4969,13 @@ public class StatusBar extends SystemUI implements DemoMode,      }      void awakenDreams() { -        SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); +        Dependency.get(UiOffloadThread.class).submit(() -> { +            try { +                mDreamManager.awaken(); +            } catch (RemoteException e) { +                e.printStackTrace(); +            } +        });      }      @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java index 6d75cfcb38f3..a6146a625193 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java @@ -22,7 +22,7 @@ import android.util.ArrayMap;  import com.android.systemui.Dependency;  import com.android.systemui.plugins.Plugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;  import com.android.systemui.tuner.TunerService;  import com.android.systemui.tuner.TunerService.Tunable; @@ -71,7 +71,7 @@ public class ExtensionControllerImpl implements ExtensionController {          @Override          public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) { -            return withPlugin(cls, PluginManager.getAction(cls)); +            return withPlugin(cls, PluginManager.Helper.getAction(cls));          }          @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index e9efaa14ef7c..0a72c3f9e8d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -17,10 +17,7 @@  package com.android.systemui.statusbar.policy;  import android.app.ActivityManager; -import android.content.BroadcastReceiver;  import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter;  import android.net.ConnectivityManager;  import android.net.wifi.WifiManager;  import android.os.UserManager; @@ -38,14 +35,13 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);      private final ArrayList<Callback> mCallbacks = new ArrayList<>(); -    private final WifiStateReceiver mWifiStateReceiver = new WifiStateReceiver();      private final ConnectivityManager mConnectivityManager;      private final WifiManager mWifiManager;      private final Context mContext;      private int mHotspotState;      private int mNumConnectedDevices; -    private boolean mWaitingForCallback; +    private boolean mWaitingForTerminalState;      public HotspotControllerImpl(Context context) {          mContext = context; @@ -63,7 +59,9 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof      public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {          pw.println("HotspotController state:"); -        pw.print("  mHotspotEnabled="); pw.println(stateToString(mHotspotState)); +        pw.print("  mHotspotState="); pw.println(stateToString(mHotspotState)); +        pw.print("  mNumConnectedDevices="); pw.println(mNumConnectedDevices); +        pw.print("  mWaitingForTerminalState="); pw.println(mWaitingForTerminalState);      }      private static String stateToString(int hotspotState) { @@ -99,7 +97,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof          if (DEBUG) Log.d(TAG, "removeCallback " + callback);          synchronized (mCallbacks) {              mCallbacks.remove(callback); -              updateWifiStateListeners(!mCallbacks.isEmpty());          }      } @@ -112,7 +109,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof       * @param shouldListen whether we should start listening to various wifi statuses       */      private void updateWifiStateListeners(boolean shouldListen) { -        mWifiStateReceiver.setListening(shouldListen);          if (shouldListen) {              mWifiManager.registerSoftApCallback(                      this, @@ -129,21 +125,27 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof      @Override      public boolean isHotspotTransient() { -        return mWaitingForCallback || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING); +        return mWaitingForTerminalState || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING);      }      @Override      public void setHotspotEnabled(boolean enabled) { -        if (mWaitingForCallback) { -            if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for callback."); +        if (mWaitingForTerminalState) { +            if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for terminal state.");              return;          }          if (enabled) { -            OnStartTetheringCallback callback = new OnStartTetheringCallback(); -            mWaitingForCallback = true; +            mWaitingForTerminalState = true;              if (DEBUG) Log.d(TAG, "Starting tethering"); -            mConnectivityManager.startTethering( -                    ConnectivityManager.TETHERING_WIFI, false, callback); +            mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false, +                    new ConnectivityManager.OnStartTetheringCallback() { +                        @Override +                        public void onTetheringFailed() { +                            if (DEBUG) Log.d(TAG, "onTetheringFailed"); +                            maybeResetSoftApState(); +                            fireHotspotChangedCallback(); +                        } +                    });          } else {              mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);          } @@ -155,99 +157,56 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof      }      /** -     * Sends a hotspot changed callback with the new enabled status. Wraps -     * {@link #fireHotspotChangedCallback(boolean, int)} and assumes that the number of devices has -     * not changed. -     * -     * @param enabled whether the hotspot is enabled -     */ -    private void fireHotspotChangedCallback(boolean enabled) { -        fireHotspotChangedCallback(enabled, mNumConnectedDevices); -    } - -    /** -     * Sends a hotspot changed callback with the new enabled status & the number of devices -     * connected to the hotspot. Be careful when calling over multiple threads, especially if one of -     * them is the main thread (as it can be blocked). -     * -     * @param enabled whether the hotspot is enabled -     * @param numConnectedDevices number of devices connected to the hotspot +     * Sends a hotspot changed callback. +     * Be careful when calling over multiple threads, especially if one of them is the main thread +     * (as it can be blocked).       */ -    private void fireHotspotChangedCallback(boolean enabled, int numConnectedDevices) { +    private void fireHotspotChangedCallback() {          synchronized (mCallbacks) {              for (Callback callback : mCallbacks) { -                callback.onHotspotChanged(enabled, numConnectedDevices); +                callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices);              }          }      }      @Override      public void onStateChanged(int state, int failureReason) { -        // Do nothing - we don't care about changing anything here. -    } +        // Update internal hotspot state for tracking before using any enabled/callback methods. +        mHotspotState = state; + +        maybeResetSoftApState(); +        if (!isHotspotEnabled()) { +            // Reset num devices if the hotspot is no longer enabled so we don't get ghost +            // counters. +            mNumConnectedDevices = 0; +        } -    @Override -    public void onNumClientsChanged(int numConnectedDevices) { -        mNumConnectedDevices = numConnectedDevices; -        fireHotspotChangedCallback(isHotspotEnabled(), numConnectedDevices); +        fireHotspotChangedCallback();      } -    private final class OnStartTetheringCallback extends -            ConnectivityManager.OnStartTetheringCallback { -        @Override -        public void onTetheringStarted() { -            if (DEBUG) Log.d(TAG, "onTetheringStarted"); -            mWaitingForCallback = false; -            // Don't fire a callback here, instead wait for the next update from wifi. +    private void maybeResetSoftApState() { +        if (!mWaitingForTerminalState) { +            return; // Only reset soft AP state if enabled from this controller.          } - -        @Override -        public void onTetheringFailed() { -            if (DEBUG) Log.d(TAG, "onTetheringFailed"); -            mWaitingForCallback = false; -            // TODO(b/110697252): stopTethering must be called to reset soft ap state after failure -            mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); -            fireHotspotChangedCallback(isHotspotEnabled()); -          // TODO: Show error. +        switch (mHotspotState) { +            case WifiManager.WIFI_AP_STATE_FAILED: +                // TODO(b/110697252): must be called to reset soft ap state after failure +                mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); +                // Fall through +            case WifiManager.WIFI_AP_STATE_ENABLED: +            case WifiManager.WIFI_AP_STATE_DISABLED: +                mWaitingForTerminalState = false; +                break; +            case WifiManager.WIFI_AP_STATE_ENABLING: +            case WifiManager.WIFI_AP_STATE_DISABLING: +            default: +                break;          }      } -    /** -     * Class to listen in on wifi state and update the hotspot state -     */ -    private final class WifiStateReceiver extends BroadcastReceiver { -        private boolean mRegistered; - -        public void setListening(boolean listening) { -            if (listening && !mRegistered) { -                if (DEBUG) Log.d(TAG, "Registering receiver"); -                final IntentFilter filter = new IntentFilter(); -                filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); -                mContext.registerReceiver(this, filter); -                mRegistered = true; -            } else if (!listening && mRegistered) { -                if (DEBUG) Log.d(TAG, "Unregistering receiver"); -                mContext.unregisterReceiver(this); -                mRegistered = false; -            } -        } - -        @Override -        public void onReceive(Context context, Intent intent) { -            int state = intent.getIntExtra( -                    WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); -            if (DEBUG) Log.d(TAG, "onReceive " + state); - -            // Update internal hotspot state for tracking before using any enabled/callback methods. -            mHotspotState = state; - -            if (!isHotspotEnabled()) { -                // Reset num devices if the hotspot is no longer enabled so we don't get ghost -                // counters. -                mNumConnectedDevices = 0; -            } - -            fireHotspotChangedCallback(isHotspotEnabled()); -        } +    @Override +    public void onNumClientsChanged(int numConnectedDevices) { +        mNumConnectedDevices = numConnectedDevices; +        fireHotspotChangedCallback();      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index cf394043b091..24a28cb45952 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -668,6 +668,7 @@ public class NetworkControllerImpl extends BroadcastReceiver          Locale current = mContext.getResources().getConfiguration().locale;          if (!current.equals(mLocale)) {              mLocale = current; +            mWifiSignalController.refreshLocale();              notifyAllListeners();          }      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 0233ad1c86ed..693df884690a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -73,6 +73,10 @@ public class WifiSignalController extends          return new WifiState();      } +    void refreshLocale() { +        mWifiTracker.refreshLocale(); +    } +      @Override      public void notifyListeners(SignalCallback callback) {          // only show wifi in the cluster if connected or if wifi-only diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java index c2948060d6bf..71414a266724 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -34,11 +34,10 @@ import android.util.ArraySet;  import android.view.View;  import com.android.systemui.R; -import com.android.systemui.plugins.PluginInstanceManager; -import com.android.systemui.plugins.PluginManager; -import com.android.systemui.plugins.PluginPrefs; +import com.android.systemui.shared.plugins.PluginInstanceManager; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginPrefs; -import java.util.ArrayList;  import java.util.List;  import java.util.Set; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 088630fa3f56..5aa303530ae5 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -32,7 +32,7 @@ import com.android.internal.hardware.AmbientDisplayConfiguration;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.nano.MetricsProto.MetricsEvent;  import com.android.systemui.R; -import com.android.systemui.plugins.PluginPrefs; +import com.android.systemui.shared.plugins.PluginPrefs;  public class TunerFragment extends PreferenceFragment { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 13c43f7009a1..4810b0b91c10 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -18,6 +18,7 @@ package com.android.systemui.volume;  import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;  import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; +import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;  import static android.media.AudioManager.RINGER_MODE_NORMAL;  import static android.media.AudioManager.RINGER_MODE_SILENT;  import static android.media.AudioManager.RINGER_MODE_VIBRATE; @@ -34,6 +35,7 @@ import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED  import android.accessibilityservice.AccessibilityServiceInfo;  import android.animation.ObjectAnimator;  import android.annotation.SuppressLint; +import android.app.ActivityManager;  import android.app.Dialog;  import android.app.KeyguardManager;  import android.content.ContentResolver; @@ -129,6 +131,7 @@ public class VolumeDialogImpl implements VolumeDialog {      private ConfigurableTexts mConfigurableTexts;      private final SparseBooleanArray mDynamic = new SparseBooleanArray();      private final KeyguardManager mKeyguard; +    private final ActivityManager mActivityManager;      private final AccessibilityManagerWrapper mAccessibilityMgr;      private final Object mSafetyWarningLock = new Object();      private final Accessibility mAccessibility = new Accessibility(); @@ -154,6 +157,7 @@ public class VolumeDialogImpl implements VolumeDialog {          mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);          mController = Dependency.get(VolumeDialogController.class);          mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); +        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);          mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);          mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);          mShowActiveStreamOnly = showActiveStreamOnly(); @@ -431,7 +435,9 @@ public class VolumeDialogImpl implements VolumeDialog {      public void initSettingsH() {          if (mSettingsView != null) {              mSettingsView.setVisibility( -                    mDeviceProvisionedController.isCurrentUserSetup() ? VISIBLE : GONE); +                    mDeviceProvisionedController.isCurrentUserSetup() && +                            mActivityManager.getLockTaskModeState() == LOCK_TASK_MODE_NONE ? +                            VISIBLE : GONE);          }          if (mSettingsIcon != null) {              mSettingsIcon.setOnClickListener(v -> { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index e6e485740a7b..62ca3f34bd48 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -40,7 +40,7 @@ import android.widget.TextClock;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.plugins.ClockPlugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import org.junit.Before;  import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java index f8aa28dbb945..199c4c283452 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java @@ -40,9 +40,9 @@ import android.support.test.filters.SmallTest;  import android.support.test.runner.AndroidJUnit4;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;  import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -65,7 +65,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {      private @Mock IActivityTaskManager mIActivityTaskManager;      private WorkLockActivityController mController; -    private SysUiTaskStackChangeListener mTaskStackListener; +    private TaskStackChangeListener mTaskStackListener;      @Before      public void setUp() throws Exception { @@ -75,8 +75,8 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {          doReturn("com.example.test").when(mContext).getPackageName();          // Construct controller. Save the TaskStackListener for injecting events. -        final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor = -                ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class); +        final ArgumentCaptor<TaskStackChangeListener> listenerCaptor = +                ArgumentCaptor.forClass(TaskStackChangeListener.class);          mController = new WorkLockActivityController(mContext, mActivityManager,                  mIActivityTaskManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index 85cdfcc2ce09..12a122a5c734 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -14,8 +14,12 @@  package com.android.systemui.qs; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; @@ -23,15 +27,21 @@ import android.support.test.filters.SmallTest;  import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper;  import android.testing.TestableLooper.RunWithLooper; +import android.view.ViewGroup; +import android.widget.FrameLayout;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.nano.MetricsProto.MetricsEvent;  import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.qs.QSTileView;  import com.android.systemui.qs.customize.QSCustomizer;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations;  import java.util.Collections; @@ -41,19 +51,37 @@ import java.util.Collections;  public class QSPanelTest extends SysuiTestCase {      private MetricsLogger mMetricsLogger; +    private TestableLooper mTestableLooper;      private QSPanel mQsPanel; +    @Mock      private QSTileHost mHost; +    @Mock      private QSCustomizer mCustomizer; +    @Mock +    private QSTile dndTile; +    private ViewGroup mParentView; +    @Mock +    private QSDetail.Callback mCallback;      @Before      public void setup() throws Exception { -        TestableLooper.get(this).runWithLooper(() -> { +        MockitoAnnotations.initMocks(this); + +        mTestableLooper = TestableLooper.get(this); +        mTestableLooper.runWithLooper(() -> {              mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);              mQsPanel = new QSPanel(mContext, null); -            mHost = mock(QSTileHost.class); +            // Provides a parent with non-zero size for QSPanel +            mParentView = new FrameLayout(mContext); +            mParentView.addView(mQsPanel); + +            when(dndTile.getTileSpec()).thenReturn("dnd");              when(mHost.getTiles()).thenReturn(Collections.emptyList()); -            mCustomizer = mock(QSCustomizer.class); +            when(mHost.createTileView(any(), anyBoolean())).thenReturn(mock(QSTileView.class)); +              mQsPanel.setHost(mHost, mCustomizer); +            mQsPanel.addTile(dndTile, true); +            mQsPanel.setCallback(mCallback);          });      } @@ -64,4 +92,31 @@ public class QSPanelTest extends SysuiTestCase {          mQsPanel.setExpanded(false);          verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false));      } + +    @Test +    public void testOpenDetailsWithExistingTile_NoException() { +        mTestableLooper.processAllMessages(); +        mQsPanel.openDetails("dnd"); +        mTestableLooper.processAllMessages(); + +        verify(mCallback).onShowingDetail(any(), anyInt(), anyInt()); +    } + +/*    @Test +    public void testOpenDetailsWithNullParameter_NoException() { +        mTestableLooper.processAllMessages(); +        mQsPanel.openDetails(null); +        mTestableLooper.processAllMessages(); + +        verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); +    }*/ + +    @Test +    public void testOpenDetailsWithNonExistingTile_NoException() { +        mTestableLooper.processAllMessages(); +        mQsPanel.openDetails("invalid-name"); +        mTestableLooper.processAllMessages(); + +        verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); +    }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java index 19974f8fc710..6d1ff8c06acf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java @@ -12,7 +12,7 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import static junit.framework.Assert.assertFalse;  import static junit.framework.Assert.assertNotNull; @@ -27,8 +27,10 @@ import static org.mockito.Mockito.when;  import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.PluginInstanceManager.PluginInfo; -import com.android.systemui.plugins.VersionInfo.InvalidVersionException; +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo; +import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;  import com.android.systemui.plugins.annotations.Requires;  import org.junit.After; diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java index 438f9e49699b..3c7020569db4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java @@ -11,7 +11,7 @@   * KIND, either express or implied. See the License for the specific language governing   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import static org.junit.Assert.assertNotNull;  import static org.junit.Assert.assertNull; @@ -27,6 +27,7 @@ import android.content.Context;  import android.content.Intent;  import android.content.pm.PackageManager;  import android.net.Uri; +import android.support.test.runner.AndroidJUnit4;  import android.test.suitebuilder.annotation.SmallTest;  import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper; @@ -35,9 +36,12 @@ import android.testing.TestableLooper.RunWithLooper;  import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;  import com.android.systemui.Dependency;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.PluginInstanceManager.PluginInfo; -import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory; +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginInitializerImpl; +import com.android.systemui.plugins.PluginListener;  import com.android.systemui.plugins.annotations.ProvidesInterface; +import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo; +import com.android.systemui.shared.plugins.PluginManagerImpl.PluginInstanceManagerFactory;  import org.junit.Before;  import org.junit.Test; @@ -74,8 +78,14 @@ public class PluginManagerTest extends SysuiTestCase {          when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),                  Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))                  .thenReturn(mMockPluginInstance); -        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true, new String[0], -                mMockExceptionHandler); + +        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true, +                mMockExceptionHandler, new PluginInitializerImpl() { +            @Override +            public String[] getWhitelistedPlugins(Context context) { +                return new String[0]; +            } +        });          resetExceptionHandler();          mMockListener = mock(PluginListener.class);      } @@ -109,7 +119,12 @@ public class PluginManagerTest extends SysuiTestCase {      @RunWithLooper(setAsMainLooper = true)      public void testNonDebuggable_noWhitelist() {          mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false, -                new String[0], mMockExceptionHandler); +                mMockExceptionHandler, new PluginInitializerImpl() { +            @Override +            public String[] getWhitelistedPlugins(Context context) { +                return new String[0]; +            } +        });          resetExceptionHandler();          mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class); @@ -121,7 +136,12 @@ public class PluginManagerTest extends SysuiTestCase {      @RunWithLooper(setAsMainLooper = true)      public void testNonDebuggable_whitelistedPkg() {          mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false, -                new String[] {WHITELISTED_PACKAGE}, mMockExceptionHandler); +                mMockExceptionHandler, new PluginInitializerImpl() { +            @Override +            public String[] getWhitelistedPlugins(Context context) { +                return new String[] {WHITELISTED_PACKAGE}; +            } +        });          resetExceptionHandler();          mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java index 0b4d9b525c1b..9bad78d2d45c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/plugins/VersionInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java @@ -12,7 +12,7 @@   * permissions and limitations under the License.   */ -package com.android.systemui.plugins; +package com.android.systemui.shared.plugins;  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertTrue; @@ -20,7 +20,8 @@ import static org.junit.Assert.assertTrue;  import android.support.test.filters.SmallTest;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.VersionInfo.InvalidVersionException; +import com.android.systemui.plugins.OverlayPlugin; +import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;  import com.android.systemui.plugins.annotations.Requires;  import com.android.systemui.plugins.qs.QS;  import com.android.systemui.plugins.qs.DetailAdapter; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java index 09c19319429b..da59450af4df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java @@ -79,13 +79,14 @@ public class NonPhoneDependencyTest extends SysuiTestCase {                  Dependency.get(NotificationLockscreenUserManager.class);          NotificationViewHierarchyManager viewHierarchyManager =                  Dependency.get(NotificationViewHierarchyManager.class); +        NotificationGroupManager groupManager = Dependency.get(NotificationGroupManager.class);          when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(lockscreenUserManager); -        when(mPresenter.getGroupManager()).thenReturn( -                Dependency.get(NotificationGroupManager.class)); +        when(mPresenter.getGroupManager()).thenReturn(groupManager);          entryManager.setUpWithPresenter(mPresenter, mListContainer, mEntryManagerCallback,                  mHeadsUpManager); +        groupManager.setHeadsUpManager(mHeadsUpManager);          gutsManager.setUpWithPresenter(mPresenter, mListContainer, mCheckSaveListener,                  mOnClickListener);          notificationLogger.setUpWithEntryManager(entryManager, mListContainer); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 1e3d42ba6ede..b545e61a446a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -32,6 +32,7 @@ import android.os.Handler;  import android.os.IPowerManager;  import android.os.Looper;  import android.os.PowerManager; +import android.service.dreams.IDreamManager;  import android.support.test.annotation.UiThreadTest;  import android.support.test.filters.SmallTest;  import android.support.test.runner.AndroidJUnit4; @@ -39,7 +40,6 @@ import android.support.test.runner.AndroidJUnit4;  import com.android.systemui.ExpandHelper;  import com.android.systemui.R;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SystemServicesProxy;  import com.android.systemui.statusbar.EmptyShadeView;  import com.android.systemui.statusbar.StatusBarState;  import com.android.systemui.statusbar.NotificationPresenter; @@ -91,7 +91,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      @Mock private NotificationData mNotificationData;      @Mock private NotificationRemoteInputManager mRemoteInputManager;      @Mock private RemoteInputController mRemoteInputController; -    @Mock private SystemServicesProxy mSystemServicesProxy; +    @Mock private IDreamManager mDreamManager;      private PowerManager mPowerManager;      private TestableNotificationEntryManager mEntryManager; @@ -111,7 +111,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {          mPowerManager = new PowerManager(mContext, powerManagerService,                  Handler.createAsync(Looper.myLooper())); -        mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager, +        mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager,                  mContext);          mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, mHeadsUpManager,                  mNotificationData); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java new file mode 100644 index 000000000000..b5f67c06b2d1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.notification.stack; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockitoSession; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.animation.Animator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +import android.graphics.Rect; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.Looper; +import android.os.PowerManager; +import android.service.notification.StatusBarNotification; +import android.support.test.annotation.UiThreadTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.testing.TestableLooper.RunWithLooper; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.MotionEvent; + +import com.android.systemui.SwipeHelper; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationMenuRow; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; + +import java.util.ArrayList; + +/** + * Tests for {@link NotificationSwipeHelper}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class NotificationSwipeHelperTest extends SysuiTestCase { + +    private NotificationSwipeHelper mSwipeHelper; +    private NotificationSwipeHelper.NotificationCallback mCallback; +    private NotificationMenuRowPlugin.OnMenuEventListener mListener; +    private View mView; +    private MotionEvent mEvent; +    private NotificationMenuRowPlugin mMenuRow; +    private Handler mHandler; +    private ExpandableNotificationRow mNotificationRow; +    private Runnable mFalsingCheck; + +    @Rule public MockitoRule mockito = MockitoJUnit.rule(); + +    @Before +    @UiThreadTest +    public void setUp() throws Exception { +        mCallback = mock(NotificationSwipeHelper.NotificationCallback.class); +        mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class); +        mSwipeHelper = spy(new NotificationSwipeHelper(SwipeHelper.X, mCallback, mContext, mListener)); +        mView = mock(View.class); +        mEvent = mock(MotionEvent.class); +        mMenuRow = mock(NotificationMenuRowPlugin.class); +        mNotificationRow = mock(ExpandableNotificationRow.class); +        mHandler = mock(Handler.class); +        mFalsingCheck = mock(Runnable.class); +    } + +    @Test +    public void testSetExposedMenuView() { +        assertEquals("intialized with null exposed menu view", null, +                mSwipeHelper.getExposedMenuView()); +        mSwipeHelper.setExposedMenuView(mView); +        assertEquals("swipe helper has correct exposedMenuView after setExposedMenuView to a view", +                mView, mSwipeHelper.getExposedMenuView()); +        mSwipeHelper.setExposedMenuView(null); +        assertEquals("swipe helper has null exposedMenuView after setExposedMenuView to null", +                null, mSwipeHelper.getExposedMenuView()); +    } + +    @Test +    public void testClearExposedMenuView() { +        doNothing().when(mSwipeHelper).setExposedMenuView(mView); +        mSwipeHelper.clearExposedMenuView(); +        verify(mSwipeHelper, times(1)).setExposedMenuView(null); +    } + +    @Test +    public void testGetTranslatingParentView() { +        assertEquals("intialized with null translating parent view", null, +                mSwipeHelper.getTranslatingParentView()); +        mSwipeHelper.setTranslatingParentView(mView); +        assertEquals("has translating parent view after setTranslatingParentView with a view", +                mView, mSwipeHelper.getTranslatingParentView()); +    } + +    @Test +    public void testClearTranslatingParentView() { +        doNothing().when(mSwipeHelper).setTranslatingParentView(null); +        mSwipeHelper.clearTranslatingParentView(); +        verify(mSwipeHelper, times(1)).setTranslatingParentView(null); +    } + +    @Test +    public void testSetCurrentMenuRow() { +        assertEquals("currentMenuRow initializes to null", null, +                mSwipeHelper.getCurrentMenuRow()); +        mSwipeHelper.setCurrentMenuRow(mMenuRow); +        assertEquals("currentMenuRow set correctly after setCurrentMenuRow", mMenuRow, +                mSwipeHelper.getCurrentMenuRow()); +        mSwipeHelper.setCurrentMenuRow(null); +        assertEquals("currentMenuRow set to null after setCurrentMenuRow to null", +                null, mSwipeHelper.getCurrentMenuRow()); +    } + +    @Test +    public void testClearCurrentMenuRow() { +        doNothing().when(mSwipeHelper).setCurrentMenuRow(null); +        mSwipeHelper.clearCurrentMenuRow(); +        verify(mSwipeHelper, times(1)).setCurrentMenuRow(null); +    } + +    @Test +    public void testOnDownUpdate_ExpandableNotificationRow() { +        when(mSwipeHelper.getHandler()).thenReturn(mHandler); +        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck); +        doNothing().when(mSwipeHelper).resetExposedMenuView(true, false); +        doNothing().when(mSwipeHelper).clearCurrentMenuRow(); +        doNothing().when(mSwipeHelper).initializeRow(any()); + +        mSwipeHelper.onDownUpdate(mNotificationRow, mEvent); + +        verify(mSwipeHelper, times(1)).clearCurrentMenuRow(); +        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck); +        verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false); +        verify(mSwipeHelper, times(1)).initializeRow(mNotificationRow); +    } + +    @Test +    public void testOnDownUpdate_notExpandableNotificationRow() { +        when(mSwipeHelper.getHandler()).thenReturn(mHandler); +        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck); +        doNothing().when(mSwipeHelper).resetExposedMenuView(true, false); +        doNothing().when(mSwipeHelper).clearCurrentMenuRow(); +        doNothing().when(mSwipeHelper).initializeRow(any()); + +        mSwipeHelper.onDownUpdate(mView, mEvent); + +        verify(mSwipeHelper, times(1)).clearCurrentMenuRow(); +        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck); +        verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false); +        verify(mSwipeHelper, times(0)).initializeRow(any()); +    } + +    @Test +    public void testOnMoveUpdate_menuRow() { +        when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow); +        when(mSwipeHelper.getHandler()).thenReturn(mHandler); +        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck); + +        mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10); + +        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck); +        verify(mMenuRow, times(1)).onTouchMove(10); +    } + +    @Test +    public void testOnMoveUpdate_noMenuRow() { +        when(mSwipeHelper.getHandler()).thenReturn(mHandler); +        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck); + +        mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10); + +        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck); +    } + +    @Test +    public void testHandleUpEvent_noMenuRow() { +        assertFalse("Menu row does not exist", +                mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0)); +    } + +    @Test +    public void testHandleUpEvent_menuRow() { +        when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow); +        doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow); + +        assertTrue("Menu row exists", +                mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0)); +        verify(mMenuRow, times(1)).onTouchEnd(); +        verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow); +    } + +    @Test +    public void testDismissChild_notExpanded() { +        when(mCallback.isExpanded()).thenReturn(false); +        doNothing().when(mSwipeHelper).superDismissChild(mView, 0, false); +        doNothing().when(mSwipeHelper).handleMenuCoveredOrDismissed(); + +        mSwipeHelper.dismissChild(mView, 0, false); + +        verify(mSwipeHelper, times(1)).superDismissChild(mView, 0, false); +        verify(mCallback, times(0)).handleChildViewDismissed(mView); +        verify(mCallback, times(1)).onDismiss(); +        verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed(); +    } + +    @Test +    public void testSnapchild_targetIsZero() { +        doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0); +        mSwipeHelper.snapChild(mView, 0, 0); + +        verify(mCallback, times(1)).onDragCancelled(mView); +        verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0); +        verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed(); +    } + + +    @Test +    public void testSnapchild_targetNotZero() { +        doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0); +        mSwipeHelper.snapChild(mView, 10, 0); + +        verify(mCallback, times(1)).onDragCancelled(mView); +        verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0); +        verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed(); +    } + +    @Test +    public void testSnooze() { +        StatusBarNotification sbn = mock(StatusBarNotification.class); +        SnoozeOption snoozeOption = mock(SnoozeOption.class); +        mSwipeHelper.snooze(sbn, snoozeOption); +        verify(mCallback, times(1)).onSnooze(sbn, snoozeOption); +    } + +    @Test +    public void testGetViewTranslationAnimator_notExpandableNotificationRow() { +        Animator animator = mock(Animator.class); +        AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class); +        doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener); + +        assertEquals("returns the correct animator from super", animator, +                mSwipeHelper.getViewTranslationAnimator(mView, 0, listener)); + +        verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener); +    } + +    @Test +    public void testGetViewTranslationAnimator_expandableNotificationRow() { +        Animator animator = mock(Animator.class); +        AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class); +        doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener); + +        assertEquals("returns the correct animator from super when view is an ENR", animator, +                mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener)); + +        verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener); +    } + +    @Test +    public void testSetTranslation() { +        mSwipeHelper.setTranslation(mNotificationRow, 0); +        verify(mNotificationRow, times(1)).setTranslation(0); +    } + +    @Test +    public void testGetTranslation() { +        doReturn(30f).when(mNotificationRow).getTranslation(); + +        assertEquals("Returns getTranslation for the ENR", +                mSwipeHelper.getTranslation(mNotificationRow), 30f); + +        verify(mNotificationRow, times(1)).getTranslation(); +    } + +    @Test +    public void testDismiss() { +        doNothing().when(mSwipeHelper).dismissChild(mView, 0, true); +        doReturn(false).when(mSwipeHelper).swipedFastEnough(); + +        mSwipeHelper.dismiss(mView, 0); + +        verify(mSwipeHelper, times(1)).swipedFastEnough(); +        verify(mSwipeHelper, times(1)).dismissChild(mView, 0, true); +    } + +    @Test +    public void testSnapOpen() { +        doNothing().when(mSwipeHelper).snapChild(mView, 30, 0); + +        mSwipeHelper.snapOpen(mView, 30, 0); + +        verify(mSwipeHelper, times(1)).snapChild(mView, 30, 0); +    } + +    @Test +    public void testSnapClosed() { +        doNothing().when(mSwipeHelper).snapChild(mView, 0, 0); + +        mSwipeHelper.snapClosed(mView, 0); + +        verify(mSwipeHelper, times(1)).snapChild(mView, 0, 0); +    } + +    @Test +    public void testGetMinDismissVelocity() { +        doReturn(30f).when(mSwipeHelper).getEscapeVelocity(); + +        assertEquals("Returns getEscapeVelocity", 30f, mSwipeHelper.getMinDismissVelocity()); +    } + +    @Test +    public void onMenuShown_noAntiFalsing() { +        doNothing().when(mSwipeHelper).setExposedMenuView(mView); +        doReturn(mView).when(mSwipeHelper).getTranslatingParentView(); +        doReturn(mHandler).when(mSwipeHelper).getHandler(); +        doReturn(false).when(mCallback).isAntiFalsingNeeded(); +        doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck(); + +        mSwipeHelper.onMenuShown(mView); + +        verify(mSwipeHelper, times(1)).setExposedMenuView(mView); +        verify(mCallback, times(1)).onDragCancelled(mView); +        verify(mCallback, times(1)).isAntiFalsingNeeded(); + +        verify(mHandler, times(0)).removeCallbacks(mFalsingCheck); +        verify(mHandler, times(0)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY); +    } + +    @Test +    public void onMenuShown_antiFalsing() { +        doNothing().when(mSwipeHelper).setExposedMenuView(mView); +        doReturn(mView).when(mSwipeHelper).getTranslatingParentView(); +        doReturn(mHandler).when(mSwipeHelper).getHandler(); +        doReturn(true).when(mCallback).isAntiFalsingNeeded(); +        doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck(); + +        mSwipeHelper.onMenuShown(mView); + +        verify(mSwipeHelper, times(1)).setExposedMenuView(mView); +        verify(mCallback, times(1)).onDragCancelled(mView); +        verify(mCallback, times(1)).isAntiFalsingNeeded(); + +        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck); +        verify(mHandler, times(1)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY); +    } + +    @Test +    public void testResetExposedMenuView_noReset() { +        doReturn(false).when(mSwipeHelper).shouldResetMenu(false); +        doNothing().when(mSwipeHelper).clearExposedMenuView(); + +        mSwipeHelper.resetExposedMenuView(false, false); + +        verify(mSwipeHelper, times(1)).shouldResetMenu(false); + +        // should not clear exposed menu row +        verify(mSwipeHelper, times(0)).clearExposedMenuView(); +    } + +    @Test +    public void testResetExposedMenuView_animate() { +        Animator animator = mock(Animator.class); + +        doReturn(true).when(mSwipeHelper).shouldResetMenu(false); +        doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView(); +        doReturn(false).when(mNotificationRow).isRemoved(); +        doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null); +        doNothing().when(mSwipeHelper).clearExposedMenuView(); + +        mSwipeHelper.resetExposedMenuView(true, false); + +        verify(mSwipeHelper, times(1)).shouldResetMenu(false); + +        // should retrieve and start animator +        verify(mSwipeHelper, times(1)).getViewTranslationAnimator(mNotificationRow, 0, null); +        verify(animator, times(1)).start(); + +        // should not reset translation on row directly +        verify(mNotificationRow, times(0)).resetTranslation(); + +        // should clear exposed menu row +        verify(mSwipeHelper, times(1)).clearExposedMenuView(); +    } + + +    @Test +    public void testResetExposedMenuView_noAnimate() { +        Animator animator = mock(Animator.class); + +        doReturn(true).when(mSwipeHelper).shouldResetMenu(false); +        doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView(); +        doReturn(false).when(mNotificationRow).isRemoved(); +        doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null); +        doNothing().when(mSwipeHelper).clearExposedMenuView(); + +        mSwipeHelper.resetExposedMenuView(false, false); + +        verify(mSwipeHelper, times(1)).shouldResetMenu(false); + +        // should not retrieve and start animator +        verify(mSwipeHelper, times(0)).getViewTranslationAnimator(mNotificationRow, 0, null); +        verify(animator, times(0)).start(); + +        // should reset translation on row directly +        verify(mNotificationRow, times(1)).resetTranslation(); + +        // should clear exposed menu row +        verify(mSwipeHelper, times(1)).clearExposedMenuView(); +    } + +    @Test +    public void testIsTouchInView() { +        assertEquals("returns false when view is null", false, +                NotificationSwipeHelper.isTouchInView(mEvent, null)); + +        doReturn(5f).when(mEvent).getRawX(); +        doReturn(10f).when(mEvent).getRawY(); + +        doReturn(20).when(mView).getWidth(); +        doReturn(20).when(mView).getHeight(); + +        Answer answer = (Answer) invocation -> { +            int[] arr = invocation.getArgument(0); +            arr[0] = 0; +            arr[1] = 0; +            return null; +        }; +        doAnswer(answer).when(mView).getLocationOnScreen(any()); + +        assertTrue("Touch is within the view", +                mSwipeHelper.isTouchInView(mEvent, mView)); + +        doReturn(50f).when(mEvent).getRawX(); + +        assertFalse("Touch is not within the view", +                mSwipeHelper.isTouchInView(mEvent, mView)); +    } + +    @Test +    public void testIsTouchInView_expandable() { +        assertEquals("returns false when view is null", false, +                NotificationSwipeHelper.isTouchInView(mEvent, null)); + +        doReturn(5f).when(mEvent).getRawX(); +        doReturn(10f).when(mEvent).getRawY(); + +        doReturn(20).when(mNotificationRow).getWidth(); +        doReturn(20).when(mNotificationRow).getActualHeight(); + +        Answer answer = (Answer) invocation -> { +            int[] arr = invocation.getArgument(0); +            arr[0] = 0; +            arr[1] = 0; +            return null; +        }; +        doAnswer(answer).when(mNotificationRow).getLocationOnScreen(any()); + +        assertTrue("Touch is within the view", +                mSwipeHelper.isTouchInView(mEvent, mNotificationRow)); + +        doReturn(50f).when(mEvent).getRawX(); + +        assertFalse("Touch is not within the view", +                mSwipeHelper.isTouchInView(mEvent, mNotificationRow)); +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 5006b0b29b0c..da93327061a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -50,6 +50,7 @@ import android.os.Looper;  import android.os.PowerManager;  import android.os.RemoteException;  import android.os.UserHandle; +import android.service.dreams.IDreamManager;  import android.service.notification.StatusBarNotification;  import android.support.test.filters.SmallTest;  import android.support.test.metricshelper.MetricsAsserts; @@ -119,9 +120,9 @@ public class StatusBarTest extends SysuiTestCase {      @Mock private KeyguardIndicationController mKeyguardIndicationController;      @Mock private NotificationStackScrollLayout mStackScroller;      @Mock private HeadsUpManagerPhone mHeadsUpManager; -    @Mock private SystemServicesProxy mSystemServicesProxy;      @Mock private NotificationPanelView mNotificationPanelView;      @Mock private IStatusBarService mBarService; +    @Mock private IDreamManager mDreamManager;      @Mock private ScrimController mScrimController;      @Mock private ArrayList<Entry> mNotificationList;      @Mock private BiometricUnlockController mBiometricUnlockController; @@ -194,8 +195,7 @@ public class StatusBarTest extends SysuiTestCase {              return null;          }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any()); -        mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager, -                mContext); +        mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager, mContext);          when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);          mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,                  mKeyguardIndicationController, mStackScroller, mHeadsUpManager, @@ -358,12 +358,12 @@ public class StatusBarTest extends SysuiTestCase {      }      @Test -    public void testShouldHeadsUp_nonSuppressedGroupSummary() { +    public void testShouldHeadsUp_nonSuppressedGroupSummary() throws Exception {          when(mPowerManager.isScreenOn()).thenReturn(true);          when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);          when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);          when(mNotificationData.shouldFilterOut(any())).thenReturn(false); -        when(mSystemServicesProxy.isDreaming()).thenReturn(false); +        when(mDreamManager.isDreaming()).thenReturn(false);          when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);          Notification n = new Notification.Builder(getContext(), "a") @@ -379,12 +379,12 @@ public class StatusBarTest extends SysuiTestCase {      }      @Test -    public void testShouldHeadsUp_suppressedGroupSummary() { +    public void testShouldHeadsUp_suppressedGroupSummary() throws Exception {          when(mPowerManager.isScreenOn()).thenReturn(true);          when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);          when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);          when(mNotificationData.shouldFilterOut(any())).thenReturn(false); -        when(mSystemServicesProxy.isDreaming()).thenReturn(false); +        when(mDreamManager.isDreaming()).thenReturn(false);          when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);          Notification n = new Notification.Builder(getContext(), "a") @@ -400,11 +400,11 @@ public class StatusBarTest extends SysuiTestCase {      }      @Test -    public void testShouldHeadsUp_suppressedHeadsUp() { +    public void testShouldHeadsUp_suppressedHeadsUp() throws Exception {          when(mPowerManager.isScreenOn()).thenReturn(true);          when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);          when(mNotificationData.shouldFilterOut(any())).thenReturn(false); -        when(mSystemServicesProxy.isDreaming()).thenReturn(false); +        when(mDreamManager.isDreaming()).thenReturn(false);          when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);          when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true); @@ -418,11 +418,11 @@ public class StatusBarTest extends SysuiTestCase {      }      @Test -    public void testShouldHeadsUp_noSuppressedHeadsUp() { +    public void testShouldHeadsUp_noSuppressedHeadsUp() throws Exception {          when(mPowerManager.isScreenOn()).thenReturn(true);          when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);          when(mNotificationData.shouldFilterOut(any())).thenReturn(false); -        when(mSystemServicesProxy.isDreaming()).thenReturn(false); +        when(mDreamManager.isDreaming()).thenReturn(false);          when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);          when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false); @@ -690,10 +690,10 @@ public class StatusBarTest extends SysuiTestCase {      public static class TestableNotificationEntryManager extends NotificationEntryManager { -        public TestableNotificationEntryManager(SystemServicesProxy systemServicesProxy, +        public TestableNotificationEntryManager(IDreamManager dreamManager,                  PowerManager powerManager, Context context) {              super(context); -            mSystemServicesProxy = systemServicesProxy; +            mDreamManager = dreamManager;              mPowerManager = powerManager;          } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java index b22a6468f5fa..1cceefa7910c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java @@ -33,7 +33,7 @@ import com.android.systemui.SysuiTestCase;  import com.android.systemui.plugins.OverlayPlugin;  import com.android.systemui.plugins.Plugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;  import com.android.systemui.statusbar.policy.ExtensionController.Extension;  import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory; diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java index 0a83a896dfaf..5f54bceb6b9b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java @@ -14,12 +14,11 @@  package com.android.systemui.utils.leaks; -import android.content.Context;  import android.testing.LeakCheck;  import com.android.systemui.plugins.Plugin;  import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  public class FakePluginManager implements PluginManager { diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java index ecda9620f7fe..f47912623e1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java @@ -20,7 +20,7 @@ import android.testing.LeakCheck;  import android.util.ArrayMap;  import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.PluginManager; +import com.android.systemui.shared.plugins.PluginManager;  import com.android.systemui.statusbar.phone.ManagedProfileController;  import com.android.systemui.statusbar.phone.StatusBarIconController;  import com.android.systemui.statusbar.policy.BatteryController; diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 90c10fdcbfde..5e87707c39e6 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -5926,7 +5926,7 @@ message MetricsEvent {      // Tag used to determine what type of charging was started/ended      // 1 = Plugged AC      // 2 = Plugged USB -    // 3 = Wireless +    // 4 = Wireless      FIELD_PLUG_TYPE = 1421;      // ACTION: USB-C Connector connected. @@ -6447,7 +6447,7 @@ message MetricsEvent {      // OPEN: Settings > System > Input & Gesture > Reach up gesture      // OS: Q -    SETTINGS_GESTURE_REACH = 1557; +    SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557;      // OPEN: Emergency dialer opened      // CLOSE: Emergency dialer closed diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java new file mode 100644 index 000000000000..5bec1a94e915 --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java @@ -0,0 +1,54 @@ +package com.android.server.backup.encryption.chunk; + +import android.util.proto.ProtoInputStream; + +import java.io.IOException; + +/** + * Information about a chunk entry in a protobuf. Only used for reading from a {@link + * ProtoInputStream}. + */ +public class Chunk { +    /** +     * Reads a Chunk from a {@link ProtoInputStream}. Expects the message to be of format {@link +     * ChunksMetadataProto.Chunk}. +     * +     * @param inputStream currently at a {@link ChunksMetadataProto.Chunk} message. +     * @throws IOException when the message is not structured as expected or a field can not be +     *     read. +     */ +    static Chunk readFromProto(ProtoInputStream inputStream) throws IOException { +        Chunk result = new Chunk(); + +        while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +            switch (inputStream.getFieldNumber()) { +                case (int) ChunksMetadataProto.Chunk.HASH: +                    result.mHash = inputStream.readBytes(ChunksMetadataProto.Chunk.HASH); +                    break; +                case (int) ChunksMetadataProto.Chunk.LENGTH: +                    result.mLength = inputStream.readInt(ChunksMetadataProto.Chunk.LENGTH); +                    break; +            } +        } + +        return result; +    } + +    private int mLength; +    private byte[] mHash; + +    /** Private constructor. This class should only be instantiated by calling readFromProto. */ +    private Chunk() { +        // Set default values for fields in case they are not available in the proto. +        mHash = new byte[]{}; +        mLength = 0; +    } + +    public int getLength() { +        return mLength; +    } + +    public byte[] getHash() { +        return mHash; +    } +}
\ No newline at end of file diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java new file mode 100644 index 000000000000..2d2e88afccf1 --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import android.annotation.Nullable; +import android.util.proto.ProtoInputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Chunk listing in a format optimized for quick look-up of chunks via their hash keys. This is + * useful when building an incremental backup. After a chunk has been produced, the algorithm can + * quickly look up whether the chunk existed in the previous backup by checking this chunk listing. + * It can then tell the server to use that chunk, through telling it the position and length of the + * chunk in the previous backup's blob. + */ +public class ChunkListing { +    /** +     * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format +     * {@link ChunksMetadataProto.ChunkListing}. +     * +     * @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message. +     * @throws IOException when the message is not structured as expected or a field can not be +     *     read. +     */ +    public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException { +        Map<ChunkHash, Entry> entries = new HashMap(); + +        long start = 0; + +        while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +            if (inputStream.getFieldNumber() == (int) ChunksMetadataProto.ChunkListing.CHUNKS) { +                long chunkToken = inputStream.start(ChunksMetadataProto.ChunkListing.CHUNKS); +                Chunk chunk = Chunk.readFromProto(inputStream); +                entries.put(new ChunkHash(chunk.getHash()), new Entry(start, chunk.getLength())); +                start += chunk.getLength(); +                inputStream.end(chunkToken); +            } +        } + +        return new ChunkListing(entries); +    } + +    private final Map<ChunkHash, Entry> mChunksByHash; + +    private ChunkListing(Map<ChunkHash, Entry> chunksByHash) { +        mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash)); +    } + +    /** Returns {@code true} if there is a chunk with the given SHA-256 MAC key in the listing. */ +    public boolean hasChunk(ChunkHash hash) { +        return mChunksByHash.containsKey(hash); +    } + +    /** +     * Returns the entry for the chunk with the given hash. +     * +     * @param hash The SHA-256 MAC of the plaintext of the chunk. +     * @return The entry, containing position and length of the chunk in the backup blob, or null if +     *     it does not exist. +     */ +    @Nullable +    public Entry getChunkEntry(ChunkHash hash) { +        return mChunksByHash.get(hash); +    } + +    /** Returns the number of chunks in this listing. */ +    public int getChunkCount() { +        return mChunksByHash.size(); +    } + +    /** Information about a chunk entry in a backup blob - i.e., its position and length. */ +    public static final class Entry { +        private final int mLength; +        private final long mStart; + +        private Entry(long start, int length) { +            mStart = start; +            mLength = length; +        } + +        /** Returns the length of the chunk in bytes. */ +        public int getLength() { +            return mLength; +        } + +        /** Returns the start position of the chunk in the backup blob, in bytes. */ +        public long getStart() { +            return mStart; +        } +    } +} diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java new file mode 100644 index 000000000000..3a6d1f62faaa --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import java.util.Arrays; + +/** + * Holds the bytes of an encrypted {@link ChunksMetadataProto.ChunkOrdering}. + * + * <p>TODO(b/116575321): After all code is ported, remove the factory method and rename + * encryptedChunkOrdering() to getBytes(). + */ +public class EncryptedChunkOrdering { +    /** +     * Constructs a new object holding the given bytes of an encrypted {@link +     * ChunksMetadataProto.ChunkOrdering}. +     * +     * <p>Note that this just holds an ordering which is already encrypted, it does not encrypt the +     * ordering. +     */ +    public static EncryptedChunkOrdering create(byte[] encryptedChunkOrdering) { +        return new EncryptedChunkOrdering(encryptedChunkOrdering); +    } + +    private final byte[] mEncryptedChunkOrdering; + +    public byte[] encryptedChunkOrdering() { +        return mEncryptedChunkOrdering; +    } + +    @Override +    public boolean equals(Object o) { +        if (this == o) { +            return true; +        } +        if (!(o instanceof EncryptedChunkOrdering)) { +            return false; +        } + +        EncryptedChunkOrdering encryptedChunkOrdering = (EncryptedChunkOrdering) o; +        return Arrays.equals( +                mEncryptedChunkOrdering, encryptedChunkOrdering.mEncryptedChunkOrdering); +    } + +    @Override +    public int hashCode() { +        return Arrays.hashCode(mEncryptedChunkOrdering); +    } + +    private EncryptedChunkOrdering(byte[] encryptedChunkOrdering) { +        mEncryptedChunkOrdering = encryptedChunkOrdering; +    } +} diff --git a/services/backup/java/com/android/server/backup/keyvalue/AgentException.java b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java new file mode 100644 index 000000000000..e2ca35116bdc --- /dev/null +++ b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +/** + * This represents something wrong with a specific package. For example: + * <ul> + *     <li>Package unknown. + *     <li>Package is not eligible for backup anymore. + *     <li>Backup agent timed out. + *     <li>Backup agent wrote protected keys. + *     <li>... + * </ul> + * + * @see KeyValueBackupTask + * @see TaskException + */ +class AgentException extends BackupException { +    static AgentException transitory() { +        return new AgentException(/* transitory */ true); +    } + +    static AgentException transitory(Exception cause) { +        return new AgentException(/* transitory */ true, cause); +    } + +    static AgentException permanent() { +        return new AgentException(/* transitory */ false); +    } + +    static AgentException permanent(Exception cause) { +        return new AgentException(/* transitory */ false, cause); +    } + +    private final boolean mTransitory; + +    private AgentException(boolean transitory) { +        mTransitory = transitory; +    } + +    private AgentException(boolean transitory, Exception cause) { +        super(cause); +        mTransitory = transitory; +    } + +    boolean isTransitory() { +        return mTransitory; +    } +} diff --git a/services/backup/java/com/android/server/backup/keyvalue/BackupException.java b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java new file mode 100644 index 000000000000..27b2d35b13ca --- /dev/null +++ b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import android.util.AndroidException; + +/** + * Key-value backup task exception. + * + * @see AgentException + * @see TaskException + */ +class BackupException extends AndroidException { +    BackupException() {} + +    BackupException(Exception cause) { +        super(cause); +    } +} diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java index a92070cfc754..bb8a1d1339a7 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java @@ -153,16 +153,18 @@ public class KeyValueBackupReporter {                  mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);      } -    void onBindAgentError(SecurityException e) { -        Slog.d(TAG, "Error in bind/backup", e); -    } -      void onAgentUnknown(String packageName) {          Slog.d(TAG, "Package does not exist, skipping");          BackupObserverUtils.sendBackupOnPackageResult(                  mObserver, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);      } +    void onBindAgentError(String packageName, SecurityException e) { +        Slog.d(TAG, "Error in bind/backup", e); +        BackupObserverUtils.sendBackupOnPackageResult( +                mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE); +    } +      void onAgentError(String packageName) {          if (MORE_DEBUG) {              Slog.i(TAG, "Agent failure for " + packageName + ", re-staging"); @@ -190,6 +192,8 @@ public class KeyValueBackupReporter {      void onCallAgentDoBackupError(String packageName, boolean callingAgent, Exception e) {          if (callingAgent) {              Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e); +            BackupObserverUtils.sendBackupOnPackageResult( +                    mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);          } else {              Slog.e(TAG, "Error before invoking agent on " + packageName + ": " + e);          } @@ -220,12 +224,8 @@ public class KeyValueBackupReporter {          }      } -    void onReadAgentDataError(String packageName, IOException e) { -        Slog.w(TAG, "Unable read backup data for " + packageName + ": " + e); -    } - -    void onWriteWidgetDataError(String packageName, IOException e) { -        Slog.w(TAG, "Unable to save widget data for " + packageName + ": " + e); +    void onAgentDataError(String packageName, IOException e) { +        Slog.w(TAG, "Unable to read/write agent data for " + packageName + ": " + e);      }      void onDigestError(NoSuchAlgorithmException e) { @@ -243,16 +243,12 @@ public class KeyValueBackupReporter {          }      } -    void onSendDataToTransport(String packageName) { +    void onTransportPerformBackup(String packageName) {          if (MORE_DEBUG) {              Slog.v(TAG, "Sending non-empty data to transport for " + packageName);          }      } -    void onNonIncrementalAndNonIncrementalRequired() { -        Slog.e(TAG, "Transport requested non-incremental but already the case"); -    } -      void onEmptyData(PackageInfo packageInfo) {          if (MORE_DEBUG) {              Slog.i(TAG, "No backup data written, not calling transport"); @@ -302,13 +298,20 @@ public class KeyValueBackupReporter {                  /* extras */ null);      } +    void onPackageBackupNonIncrementalAndNonIncrementalRequired(String packageName) { +        Slog.e(TAG, "Transport requested non-incremental but already the case"); +        BackupObserverUtils.sendBackupOnPackageResult( +                mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); +        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName); +    } +      void onPackageBackupTransportFailure(String packageName) {          BackupObserverUtils.sendBackupOnPackageResult(                  mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);          EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);      } -    void onPackageBackupError(String packageName, Exception e) { +    void onPackageBackupTransportError(String packageName, Exception e) {          Slog.e(TAG, "Transport error backing up " + packageName, e);          BackupObserverUtils.sendBackupOnPackageResult(                  mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED); diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index e915ce16a2ef..6904b3fc6b9c 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -16,6 +16,7 @@  package com.android.server.backup.keyvalue; +import static android.app.ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL;  import static android.os.ParcelFileDescriptor.MODE_CREATE;  import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;  import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; @@ -25,8 +26,8 @@ import static com.android.server.backup.BackupManagerService.KEY_WIDGET_STATE;  import static com.android.server.backup.BackupManagerService.OP_PENDING;  import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; +import android.annotation.IntDef;  import android.annotation.Nullable; -import android.app.ApplicationThreadConstants;  import android.app.IBackupAgent;  import android.app.backup.BackupAgent;  import android.app.backup.BackupDataInput; @@ -47,7 +48,6 @@ import android.os.RemoteException;  import android.os.SELinux;  import android.os.UserHandle;  import android.os.WorkSource; -import android.util.Pair;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting; @@ -77,6 +77,8 @@ import java.io.FileDescriptor;  import java.io.FileInputStream;  import java.io.FileOutputStream;  import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.security.MessageDigest;  import java.security.NoSuchAlgorithmException;  import java.util.ArrayList; @@ -173,10 +175,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      private static final AtomicInteger THREAD_COUNT = new AtomicInteger();      private static final String BLANK_STATE_FILE_NAME = "blank_state";      private static final String PM_PACKAGE = BackupManagerService.PACKAGE_MANAGER_SENTINEL; -    @VisibleForTesting -    public static final String STAGING_FILE_SUFFIX = ".data"; -    @VisibleForTesting -    public static final String NEW_STATE_FILE_SUFFIX = ".new"; +    @VisibleForTesting public static final String STAGING_FILE_SUFFIX = ".data"; +    @VisibleForTesting public static final String NEW_STATE_FILE_SUFFIX = ".new";      /**       * Creates a new {@link KeyValueBackupTask} for key-value backup operation, spins up a new @@ -244,13 +244,13 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      private final int mCurrentOpToken;      private final File mStateDirectory;      private final File mDataDirectory; +    private final File mBlankStateFile;      private final List<String> mOriginalQueue;      private final List<String> mQueue;      private final List<String> mPendingFullBackups;      private final Object mQueueLock;      @Nullable private final DataChangedJournal mJournal; -    private int mStatus;      @Nullable private PerformFullTransportBackupTask mFullBackupTask;      @Nullable private IBackupAgent mAgent;      @Nullable private PackageInfo mCurrentPackage; @@ -316,6 +316,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          mDataDirectory = mBackupManagerService.getDataDir();          mCurrentOpToken = backupManagerService.generateRandomIntegerToken();          mQueueLock = mBackupManagerService.getQueueLock(); +        mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);      }      private void registerTask() { @@ -331,45 +332,43 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      public void run() {          Process.setThreadPriority(THREAD_PRIORITY); -        boolean processQueue = startTask(); -        while (processQueue && !mQueue.isEmpty() && !mCancelled) { -            String packageName = mQueue.remove(0); -            if (PM_PACKAGE.equals(packageName)) { -                processQueue = backupPm(); -            } else { -                processQueue = backupPackage(packageName); +        int status = BackupTransport.TRANSPORT_OK; +        try { +            startTask(); +            while (!mQueue.isEmpty() && !mCancelled) { +                String packageName = mQueue.remove(0); +                try { +                    if (PM_PACKAGE.equals(packageName)) { +                        backupPm(); +                    } else { +                        backupPackage(packageName); +                    } +                } catch (AgentException e) { +                    if (e.isTransitory()) { +                        // We try again this package in the next backup pass. +                        mBackupManagerService.dataChangedImpl(packageName); +                    } +                }              } +        } catch (TaskException e) { +            if (e.isStateCompromised()) { +                mBackupManagerService.resetBackupState(mStateDirectory); +            } +            revertTask(); +            status = e.getStatus();          } -        finishTask(); +        finishTask(status);      } -    /** Returns whether to consume next queue package. */ -    private boolean handleAgentResult(@Nullable PackageInfo packageInfo, RemoteResult result) { -        if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) { -            // Not an explicit cancel, we need to flag it. -            mCancelled = true; -            mReporter.onAgentCancelled(packageInfo); -            cleanUpAgentForAgentError(); -            return false; -        } -        if (result == RemoteResult.FAILED_CANCELLED) { -            mReporter.onAgentCancelled(packageInfo); -            cleanUpAgentForAgentError(); -            return false; -        } -        if (result == RemoteResult.FAILED_TIMED_OUT) { -            mReporter.onAgentTimedOut(packageInfo); -            cleanUpAgentForAgentError(); -            return true; -        } -        Preconditions.checkState(result.isPresent()); -        long agentResult = result.get(); -        if (agentResult == BackupAgent.RESULT_ERROR) { -            mReporter.onAgentResultError(packageInfo); -            cleanUpAgentForAgentError(); -            return true; +    /** Returns transport status. */ +    private int sendDataToTransport(@Nullable PackageInfo packageInfo) +            throws AgentException, TaskException { +        try { +            return sendDataToTransport(); +        } catch (IOException e) { +            mReporter.onAgentDataError(packageInfo.packageName, e); +            throw TaskException.causedBy(e);          } -        return sendDataToTransport();      }      @Override @@ -378,11 +377,10 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      @Override      public void operationComplete(long unusedResult) {} -    /** Returns whether to consume next queue package. */ -    private boolean startTask() { +    private void startTask() throws TaskException {          if (mBackupManagerService.isBackupOperationInProgress()) {              mReporter.onSkipBackup(); -            return false; +            throw TaskException.create();          }          // Unfortunately full backup task constructor registers the task with BMS, so we have to @@ -390,11 +388,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          mFullBackupTask = createFullBackupTask(mPendingFullBackups);          registerTask(); -        mStatus = BackupTransport.TRANSPORT_OK; -          if (mQueue.isEmpty() && mPendingFullBackups.isEmpty()) {              mReporter.onEmptyQueueAtStart(); -            return false; +            return;          }          // We only backup PM if it was explicitly in the queue or if it's incremental.          boolean backupPm = mQueue.remove(PM_PACKAGE) || !mNonIncremental; @@ -415,20 +411,18 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {              if (pmState.length() <= 0) {                  mReporter.onInitializeTransport(transportName);                  mBackupManagerService.resetBackupState(mStateDirectory); -                mStatus = transport.initializeDevice(); -                mReporter.onTransportInitialized(mStatus); +                int status = transport.initializeDevice(); +                mReporter.onTransportInitialized(status); +                if (status != BackupTransport.TRANSPORT_OK) { +                    throw TaskException.stateCompromised(); +                }              } +        } catch (TaskException e) { +            throw e;          } catch (Exception e) {              mReporter.onInitializeTransportError(e); -            mStatus = BackupTransport.TRANSPORT_ERROR; -        } - -        if (mStatus != BackupTransport.TRANSPORT_OK) { -            mBackupManagerService.resetBackupState(mStateDirectory); -            return false; +            throw TaskException.stateCompromised();          } - -        return true;      }      private PerformFullTransportBackupTask createFullBackupTask(List<String> packages) { @@ -446,120 +440,82 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {                  mUserInitiated);      } -    /** Returns whether to consume next queue package. */ -    private boolean backupPm() { -        RemoteResult agentResult = null; -        try { -            mCurrentPackage = new PackageInfo(); -            mCurrentPackage.packageName = PM_PACKAGE; - -            // Since PM is running in the system process we can set up its agent directly. -            BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent(); -            mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind()); +    private void backupPm() throws TaskException { +        mReporter.onStartPackageBackup(PM_PACKAGE); +        mCurrentPackage = new PackageInfo(); +        mCurrentPackage.packageName = PM_PACKAGE; -            Pair<Integer, RemoteResult> statusAndResult = extractAgentData(PM_PACKAGE, mAgent); -            mStatus = statusAndResult.first; -            agentResult = statusAndResult.second; -        } catch (Exception e) { +        try { +            extractPmAgentData(mCurrentPackage); +            int status = sendDataToTransport(mCurrentPackage); +            cleanUpAgentForTransportStatus(status); +        } catch (AgentException | TaskException e) {              mReporter.onExtractPmAgentDataError(e); -            mStatus = BackupTransport.TRANSPORT_ERROR; -        } - -        if (mStatus != BackupTransport.TRANSPORT_OK) { -            // In this case either extractAgentData() already made the agent clean-up or we haven't -            // prepared the state for calling the agent, in either case we don't need to clean-up. -            mBackupManagerService.resetBackupState(mStateDirectory); -            return false; +            cleanUpAgentForError(e); +            // PM agent failure is task failure. +            throw TaskException.stateCompromised(e);          } - -        Preconditions.checkNotNull(agentResult); -        return handleAgentResult(mCurrentPackage, agentResult);      } -    /** Returns whether to consume next queue package. */ -    private boolean backupPackage(String packageName) { +    private void backupPackage(String packageName) throws AgentException, TaskException {          mReporter.onStartPackageBackup(packageName); -        mStatus = BackupTransport.TRANSPORT_OK; +        mCurrentPackage = getPackageForBackup(packageName); -        // Verify that the requested app is eligible for key-value backup. -        RemoteResult agentResult = null;          try { -            mCurrentPackage = mPackageManager.getPackageInfo( -                    packageName, PackageManager.GET_SIGNING_CERTIFICATES); -            ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo; -            if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) { -                // The manifest has changed. This won't happen again because the app won't be -                // requesting further backups. -                mReporter.onPackageNotEligibleForBackup(packageName); -                return true; -            } - -            if (AppBackupUtils.appGetsFullBackup(mCurrentPackage)) { -                // Initially enqueued for key-value backup, but only supports full-backup now. -                mReporter.onPackageEligibleForFullBackup(packageName); -                return true; -            } - -            if (AppBackupUtils.appIsStopped(applicationInfo)) { -                // Just as it won't receive broadcasts, we won't run it for backup. -                mReporter.onPackageStopped(packageName); -                return true; -            } +            extractAgentData(mCurrentPackage); +            int status = sendDataToTransport(mCurrentPackage); +            cleanUpAgentForTransportStatus(status); +        } catch (AgentException | TaskException e) { +            cleanUpAgentForError(e); +            throw e; +        } +    } -            try { -                mBackupManagerService.setWorkSource(new WorkSource(applicationInfo.uid)); -                IBackupAgent agent = -                        mBackupManagerService.bindToAgentSynchronous( -                                applicationInfo, -                                ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); -                if (agent != null) { -                    mAgent = agent; -                    Pair<Integer, RemoteResult> statusAndResult = -                            extractAgentData(packageName, agent); -                    mStatus = statusAndResult.first; -                    agentResult = statusAndResult.second; -                } else { -                    // Timeout waiting for the agent to bind. -                    mStatus = BackupTransport.AGENT_ERROR; -                } -            } catch (SecurityException e) { -                mReporter.onBindAgentError(e); -                mStatus = BackupTransport.AGENT_ERROR; -            } +    private PackageInfo getPackageForBackup(String packageName) throws AgentException { +        final PackageInfo packageInfo; +        try { +            packageInfo = +                    mPackageManager.getPackageInfo( +                            packageName, PackageManager.GET_SIGNING_CERTIFICATES);          } catch (PackageManager.NameNotFoundException e) { -            mStatus = BackupTransport.AGENT_UNKNOWN; -        } finally { -            mBackupManagerService.setWorkSource(null); +            mReporter.onAgentUnknown(packageName); +            throw AgentException.permanent(e);          } +        ApplicationInfo applicationInfo = packageInfo.applicationInfo; +        if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) { +            mReporter.onPackageNotEligibleForBackup(packageName); +            throw AgentException.permanent(); +        } +        if (AppBackupUtils.appGetsFullBackup(packageInfo)) { +            mReporter.onPackageEligibleForFullBackup(packageName); +            throw AgentException.permanent(); +        } +        if (AppBackupUtils.appIsStopped(applicationInfo)) { +            mReporter.onPackageStopped(packageName); +            throw AgentException.permanent(); +        } +        return packageInfo; +    } -        if (mStatus != BackupTransport.TRANSPORT_OK) { -            // In this case either extractAgentData() already made the agent clean-up or we haven't -            // prepared the state for calling the agent, in either case we don't need to clean-up. -            Preconditions.checkState(mAgent == null); - -            if (mStatus == BackupTransport.AGENT_ERROR) { +    private IBackupAgent bindAgent(PackageInfo packageInfo) throws AgentException { +        String packageName = packageInfo.packageName; +        final IBackupAgent agent; +        try { +            agent = +                    mBackupManagerService.bindToAgentSynchronous( +                            packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL); +            if (agent == null) {                  mReporter.onAgentError(packageName); -                mBackupManagerService.dataChangedImpl(packageName); -                mStatus = BackupTransport.TRANSPORT_OK; -                return true; +                throw AgentException.transitory();              } - -            if (mStatus == BackupTransport.AGENT_UNKNOWN) { -                mReporter.onAgentUnknown(packageName); -                mStatus = BackupTransport.TRANSPORT_OK; -                return true; -            } - -            // Transport-level failure, re-enqueue everything. -            revertTask(); -            return false; +        } catch (SecurityException e) { +            mReporter.onBindAgentError(packageName, e); +            throw AgentException.transitory(e);          } - -        Preconditions.checkNotNull(agentResult); -        return handleAgentResult(mCurrentPackage, agentResult); +        return agent;      } -    private void finishTask() { +    private void finishTask(int status) {          // Mark packages that we couldn't backup as pending backup.          for (String packageName : mQueue) {              mBackupManagerService.dataChangedImpl(packageName); @@ -576,7 +532,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          // If we succeeded and this is the first time we've done a backup, we can record the current          // backup dataset token.          long currentToken = mBackupManagerService.getCurrentToken(); -        if ((mStatus == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) { +        if ((status == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {              try {                  IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);                  mBackupManagerService.setCurrentToken(transport.getCurrentRestoreSet()); @@ -589,9 +545,14 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          synchronized (mQueueLock) {              mBackupManagerService.setBackupRunning(false); -            if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) { +            if (status == BackupTransport.TRANSPORT_NOT_INITIALIZED) {                  mReporter.onTransportNotInitialized(); -                triggerTransportInitializationLocked(); +                try { +                    triggerTransportInitializationLocked(); +                } catch (Exception e) { +                    mReporter.onPendingInitializeTransportError(e); +                    status = BackupTransport.TRANSPORT_ERROR; +                }              }          } @@ -605,7 +566,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          }          if (!mCancelled -                && mStatus == BackupTransport.TRANSPORT_OK +                && status == BackupTransport.TRANSPORT_OK                  && mFullBackupTask != null                  && !mPendingFullBackups.isEmpty()) {              mReporter.onStartFullBackup(mPendingFullBackups); @@ -621,7 +582,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {              mFullBackupTask.unregisterTask();          }          mTaskFinishedListener.onFinished(callerLogString); -        mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, mStatus)); +        mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, status));          mBackupManagerService.getWakelock().release();      } @@ -642,17 +603,12 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      }      @GuardedBy("mQueueLock") -    private void triggerTransportInitializationLocked() { -        try { -            IBackupTransport transport = -                    mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked"); -            mBackupManagerService.getPendingInits().add(transport.name()); -            deletePmStateFile(); -            mBackupManagerService.backupNow(); -        } catch (Exception e) { -            mReporter.onPendingInitializeTransportError(e); -            mStatus = BackupTransport.TRANSPORT_ERROR; -        } +    private void triggerTransportInitializationLocked() throws Exception { +        IBackupTransport transport = +                mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked"); +        mBackupManagerService.getPendingInits().add(transport.name()); +        deletePmStateFile(); +        mBackupManagerService.backupNow();      }      /** Removes PM state, triggering initialization in the next key-value task. */ @@ -660,35 +616,69 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          new File(mStateDirectory, PM_PACKAGE).delete();      } +    /** Same as {@link #extractAgentData(PackageInfo)}, but only for PM package. */ +    private void extractPmAgentData(PackageInfo packageInfo) throws AgentException, TaskException { +        Preconditions.checkArgument(packageInfo.packageName.equals(PM_PACKAGE)); +        BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent(); +        mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind()); +        extractAgentData(packageInfo, mAgent); +    } +      /** -     * Returns a {@link Pair}. The first of the pair contains the status. In case the status is -     * {@link BackupTransport#TRANSPORT_OK}, the second of the pair contains the agent result, -     * otherwise {@code null}. +     * Binds to the agent and extracts its backup data. If this method returns, the data in {@code +     * mBackupData} is ready to be sent to the transport, otherwise it will throw. +     * +     * <p>This method leaves agent resources (agent binder, files and file-descriptors) opened that +     * need to be cleaned up after terminating, either successfully or exceptionally. This clean-up +     * can be done with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link +     * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to +     * the transport or not. It's the caller responsibility to do the clean-up or delegate it.       */ -    private Pair<Integer, RemoteResult> extractAgentData(String packageName, IBackupAgent agent) { +    private void extractAgentData(PackageInfo packageInfo) throws AgentException, TaskException { +        mBackupManagerService.setWorkSource(new WorkSource(packageInfo.applicationInfo.uid)); +        try { +            mAgent = bindAgent(packageInfo); +            extractAgentData(packageInfo, mAgent); +        } finally { +            mBackupManagerService.setWorkSource(null); +        } +    } + +    /** +     * Calls agent {@link IBackupAgent#doBackup(ParcelFileDescriptor, ParcelFileDescriptor, +     * ParcelFileDescriptor, long, IBackupCallback, int)} and waits for the result. If this method +     * returns, the data in {@code mBackupData} is ready to be sent to the transport, otherwise it +     * will throw. +     * +     * <p>This method creates files and file-descriptors for the agent that need to be deleted and +     * closed after terminating, either successfully or exceptionally. This clean-up can be done +     * with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link +     * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to +     * the transport or not. It's the caller responsibility to do the clean-up or delegate it. +     */ +    private void extractAgentData(PackageInfo packageInfo, IBackupAgent agent) +            throws AgentException, TaskException { +        String packageName = packageInfo.packageName;          mReporter.onExtractAgentData(packageName); -        File blankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);          mSavedStateFile = new File(mStateDirectory, packageName);          mBackupDataFile = new File(mDataDirectory, packageName + STAGING_FILE_SUFFIX);          mNewStateFile = new File(mStateDirectory, packageName + NEW_STATE_FILE_SUFFIX);          mReporter.onAgentFilesReady(mBackupDataFile); -        mSavedState = null; -        mBackupData = null; -        mNewState = null; -          boolean callingAgent = false;          final RemoteResult agentResult;          try { -            File savedStateFileForAgent = (mNonIncremental) ? blankStateFile : mSavedStateFile; +            File savedStateFileForAgent = (mNonIncremental) ? mBlankStateFile : mSavedStateFile;              // MODE_CREATE to make an empty file if necessary -            mSavedState = ParcelFileDescriptor.open( -                    savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE); -            mBackupData = ParcelFileDescriptor.open( -                    mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); -            mNewState = ParcelFileDescriptor.open( -                    mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); +            mSavedState = +                    ParcelFileDescriptor.open(savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE); +            mBackupData = +                    ParcelFileDescriptor.open( +                            mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); +            mNewState = +                    ParcelFileDescriptor.open( +                            mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);              if (!SELinux.restorecon(mBackupDataFile)) {                  mReporter.onRestoreconFailed(mBackupDataFile); @@ -713,15 +703,40 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {                              "doBackup()");          } catch (Exception e) {              mReporter.onCallAgentDoBackupError(packageName, callingAgent, e); -            cleanUpAgentForAgentError(); -            // TODO: Remove the check on callingAgent when RemoteCall supports local agent calls. -            int status = -                    callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR; -            return Pair.create(status, null); +            if (callingAgent) { +                throw AgentException.transitory(e); +            } else { +                throw TaskException.create(); +            } +        } finally { +            mBlankStateFile.delete();          } -        blankStateFile.delete(); +        checkAgentResult(packageInfo, agentResult); +    } -        return Pair.create(BackupTransport.TRANSPORT_OK, agentResult); +    private void checkAgentResult(PackageInfo packageInfo, RemoteResult result) +            throws AgentException, TaskException { +        if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) { +            // Not an explicit cancel, we need to flag it. +            mCancelled = true; +            mReporter.onAgentCancelled(packageInfo); +            throw TaskException.create(); +        } +        if (result == RemoteResult.FAILED_CANCELLED) { +            mReporter.onAgentCancelled(packageInfo); +            throw TaskException.create(); +        } +        if (result == RemoteResult.FAILED_TIMED_OUT) { +            mReporter.onAgentTimedOut(packageInfo); +            throw AgentException.transitory(); +        } +        Preconditions.checkState(result.isPresent()); +        long resultCode = result.get(); +        if (resultCode == BackupAgent.RESULT_ERROR) { +            mReporter.onAgentResultError(packageInfo); +            throw AgentException.transitory(); +        } +        Preconditions.checkState(resultCode == BackupAgent.RESULT_SUCCESS);      }      private void agentFail(IBackupAgent agent, String message) { @@ -801,94 +816,79 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          }      } -    /** Returns whether to consume next queue package. */ -    private boolean sendDataToTransport() { +    /** Returns transport status. */ +    private int sendDataToTransport() throws AgentException, TaskException, IOException {          Preconditions.checkState(mBackupData != null); +        checkBackupData(mCurrentPackage.applicationInfo, mBackupDataFile);          String packageName = mCurrentPackage.packageName; -        ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo; +        writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName); -        boolean writingWidgetData = false; -        try { -            if (!validateBackupData(applicationInfo, mBackupDataFile)) { -                cleanUpAgentForAgentError(); -                return true; -            } -            writingWidgetData = true; -            writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName); -        } catch (IOException e) { -            if (writingWidgetData) { -                mReporter.onWriteWidgetDataError(packageName, e); -            } else { -                mReporter.onReadAgentDataError(packageName, e); -            } -            cleanUpAgentForAgentError(); -            revertTask(); -            return false; +        boolean nonIncremental = mSavedStateFile.length() == 0; +        int status = transportPerformBackup(mCurrentPackage, mBackupDataFile, nonIncremental); +        handleTransportStatus(status, packageName, mBackupDataFile.length()); +        return status; +    } + +    private int transportPerformBackup( +            PackageInfo packageInfo, File backupDataFile, boolean nonIncremental) +            throws TaskException { +        String packageName = packageInfo.packageName; +        long size = backupDataFile.length(); +        if (size <= 0) { +            mReporter.onEmptyData(packageInfo); +            return BackupTransport.TRANSPORT_OK;          } -        boolean nonIncremental = mSavedStateFile.length() == 0; -        long size = mBackupDataFile.length(); -        if (size > 0) { -            try (ParcelFileDescriptor backupData = -                         ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY)) { -                IBackupTransport transport = -                        mTransportClient.connectOrThrow("KVBT.sendDataToTransport()"); -                mReporter.onSendDataToTransport(packageName); -                int flags = getPerformBackupFlags(mUserInitiated, nonIncremental); +        int status; +        try (ParcelFileDescriptor backupData = +                ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) { +            IBackupTransport transport = +                    mTransportClient.connectOrThrow("KVBT.transportPerformBackup()"); +            mReporter.onTransportPerformBackup(packageName); +            int flags = getPerformBackupFlags(mUserInitiated, nonIncremental); -                mStatus = transport.performBackup(mCurrentPackage, backupData, flags); -                if (mStatus == BackupTransport.TRANSPORT_OK) { -                    mStatus = transport.finishBackup(); -                } -            } catch (Exception e) { -                mReporter.onPackageBackupError(packageName, e); -                mStatus = BackupTransport.TRANSPORT_ERROR; +            status = transport.performBackup(packageInfo, backupData, flags); +            if (status == BackupTransport.TRANSPORT_OK) { +                status = transport.finishBackup();              } -        } else { -            mReporter.onEmptyData(mCurrentPackage); -            mStatus = BackupTransport.TRANSPORT_OK; +        } catch (Exception e) { +            mReporter.onPackageBackupTransportError(packageName, e); +            throw TaskException.causedBy(e);          } -        if (nonIncremental -                && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) { -            mReporter.onNonIncrementalAndNonIncrementalRequired(); -            mStatus = BackupTransport.TRANSPORT_ERROR; +        if (nonIncremental && status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) { +            mReporter.onPackageBackupNonIncrementalAndNonIncrementalRequired(packageName); +            throw TaskException.create();          } - -        boolean processQueue = handleTransportStatus(mStatus, packageName, size); -        // We might report quota exceeded to the agent in handleTransportStatus() above, so we -        // only clean-up after it. -        cleanUpAgentForTransportStatus(mStatus); -        return processQueue; +        return status;      } -    /** Returns whether to consume next queue package. */ -    private boolean handleTransportStatus(int status, String packageName, long size) { +    private void handleTransportStatus(int status, String packageName, long size) +            throws TaskException, AgentException {          if (status == BackupTransport.TRANSPORT_OK) {              mReporter.onPackageBackupComplete(packageName, size); -            return true; -        } -        if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { -            mReporter.onPackageBackupRejected(packageName); -            return true; +            return;          }          if (status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {              mReporter.onPackageBackupNonIncrementalRequired(mCurrentPackage);              // Immediately retry the current package.              mQueue.add(0, packageName); -            return true; +            return; +        } +        if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) { +            mReporter.onPackageBackupRejected(packageName); +            throw AgentException.permanent();          }          if (status == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {              mReporter.onPackageBackupQuotaExceeded(packageName);              agentDoQuotaExceeded(mAgent, packageName, size); -            return true; +            throw AgentException.permanent();          }          // Any other error here indicates a transport-level failure.          mReporter.onPackageBackupTransportFailure(packageName); -        revertTask(); -        return false; +        throw TaskException.forStatus(status);      }      private void agentDoQuotaExceeded(@Nullable IBackupAgent agent, String packageName, long size) { @@ -908,19 +908,17 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {      }      /** -     * For system apps and pseudo-apps always return {@code true}. For regular apps returns whether -     * {@code backupDataFile} doesn't have any protected keys. -     * -     * <p>If the app has attempted to write any protected keys we also crash them. +     * For system apps and pseudo-apps never throws. For regular apps throws {@link AgentException} +     * if {@code backupDataFile} has any protected keys, also crashing the app.       */ -    private boolean validateBackupData( -            @Nullable ApplicationInfo applicationInfo, File backupDataFile) throws IOException { +    private void checkBackupData(@Nullable ApplicationInfo applicationInfo, File backupDataFile) +            throws IOException, AgentException {          if (applicationInfo == null || (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {              // System apps and pseudo-apps can write what they want. -            return true; +            return;          }          try (ParcelFileDescriptor backupData = -                     ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) { +                ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {              BackupDataInput backupDataInput = new BackupDataInput(backupData.getFileDescriptor());              while (backupDataInput.readNextHeader()) {                  String key = backupDataInput.getKey(); @@ -928,12 +926,11 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {                      mReporter.onAgentIllegalKey(mCurrentPackage, key);                      // Crash them if they wrote any protected keys.                      agentFail(mAgent, "Illegal backup key: " + key); -                    return false; +                    throw AgentException.permanent();                  }                  backupDataInput.skipEntityData();              }          } -        return true;      }      private int getPerformBackupFlags(boolean userInitiated, boolean nonIncremental) { @@ -1009,44 +1006,39 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          }      } -    /** Cleans-up after having called the agent. */ -    private void cleanUpAgentForTransportStatus(int status) { -        updateFiles(status); -        cleanUpAgent(); -    } - -    /** Cleans-up if we failed to call the agent. */ -    private void cleanUpAgentForAgentError() { -        mBackupDataFile.delete(); -        mNewStateFile.delete(); -        cleanUpAgent(); +    /** +     * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} for exceptional +     * case. +     * +     * <p>Note: Declaring exception parameter so that the caller only calls this when an exception +     * is thrown. +     */ +    private void cleanUpAgentForError(BackupException exception) { +        cleanUpAgent(StateTransaction.DISCARD_NEW);      } -    private void updateFiles(int status) { +    /** +     * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} according to +     * transport status returned in {@link #sendDataToTransport(PackageInfo)}. +     */ +    private void cleanUpAgentForTransportStatus(int status) {          switch (status) {              case BackupTransport.TRANSPORT_OK: -                mBackupDataFile.delete(); -                mNewStateFile.renameTo(mSavedStateFile); +                cleanUpAgent(StateTransaction.COMMIT_NEW);                  break;              case BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED: -                mSavedStateFile.delete(); -                mBackupDataFile.delete(); -                mNewStateFile.delete(); +                cleanUpAgent(StateTransaction.DISCARD_ALL);                  break;              default: -                // Includes: -                // * BackupTransport.TRANSPORT_PACKAGE_REJECTED -                // * BackupTransport.TRANSPORT_QUOTA_EXCEEDED -                // * BackupTransport.TRANSPORT_ERROR -                mBackupDataFile.delete(); -                mNewStateFile.delete(); -                break; +                // All other transport statuses are properly converted to agent or task exceptions. +                throw new AssertionError();          }      } -    /** Cleans-up file-descriptors and unbinds agent. */ -    private void cleanUpAgent() { -        mAgent = null; +    private void cleanUpAgent(@StateTransaction int stateTransaction) { +        applyStateTransaction(stateTransaction); +        mBackupDataFile.delete(); +        mBlankStateFile.delete();          tryCloseFileDescriptor(mSavedState, "old state");          tryCloseFileDescriptor(mBackupData, "backup data");          tryCloseFileDescriptor(mNewState, "new state"); @@ -1058,6 +1050,24 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          if (mCurrentPackage.applicationInfo != null) {              mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);          } +        mAgent = null; +    } + +    private void applyStateTransaction(@StateTransaction int stateTransaction) { +        switch (stateTransaction) { +            case StateTransaction.COMMIT_NEW: +                mNewStateFile.renameTo(mSavedStateFile); +                break; +            case StateTransaction.DISCARD_NEW: +                mNewStateFile.delete(); +                break; +            case StateTransaction.DISCARD_ALL: +                mSavedStateFile.delete(); +                mNewStateFile.delete(); +                break; +            default: +                throw new IllegalArgumentException("Unknown state transaction " + stateTransaction); +        }      }      private void tryCloseFileDescriptor(@Nullable Closeable closeable, String logName) { @@ -1079,4 +1089,16 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {          mPendingCall = null;          return result;      } + +    @IntDef({ +        StateTransaction.COMMIT_NEW, +        StateTransaction.DISCARD_NEW, +        StateTransaction.DISCARD_ALL, +    }) +    @Retention(RetentionPolicy.SOURCE) +    private @interface StateTransaction { +        int COMMIT_NEW = 0; +        int DISCARD_NEW = 1; +        int DISCARD_ALL = 2; +    }  } diff --git a/services/backup/java/com/android/server/backup/keyvalue/TaskException.java b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java new file mode 100644 index 000000000000..08d289556ca3 --- /dev/null +++ b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import android.app.backup.BackupTransport; + +import com.android.internal.util.Preconditions; + +/** + * The key-value backup task has failed, no more packages will be processed and we shouldn't attempt + * any more backups now. These can be caused by transport failures (as opposed to agent failures). + * + * @see KeyValueBackupTask + * @see AgentException + */ +class TaskException extends BackupException { +    private static final int DEFAULT_STATUS = BackupTransport.TRANSPORT_ERROR; + +    static TaskException stateCompromised() { +        return new TaskException(/* stateCompromised */ true, DEFAULT_STATUS); +    } + +    static TaskException stateCompromised(Exception cause) { +        if (cause instanceof TaskException) { +            TaskException exception = (TaskException) cause; +            return new TaskException(cause, /* stateCompromised */ true, exception.getStatus()); +        } +        return new TaskException(cause, /* stateCompromised */ true, DEFAULT_STATUS); +    } + +    static TaskException forStatus(int status) { +        Preconditions.checkArgument( +                status != BackupTransport.TRANSPORT_OK, "Exception based on TRANSPORT_OK"); +        return new TaskException(/* stateCompromised */ false, status); +    } + +    static TaskException causedBy(Exception cause) { +        if (cause instanceof TaskException) { +            return (TaskException) cause; +        } +        return new TaskException(cause, /* stateCompromised */ false, DEFAULT_STATUS); +    } + +    static TaskException create() { +        return new TaskException(/* stateCompromised */ false, DEFAULT_STATUS); +    } + +    private final boolean mStateCompromised; +    private final int mStatus; + +    private TaskException(Exception cause, boolean stateCompromised, int status) { +        super(cause); +        mStateCompromised = stateCompromised; +        mStatus = status; +    } + +    private TaskException(boolean stateCompromised, int status) { +        mStateCompromised = stateCompromised; +        mStatus = status; +    } + +    boolean isStateCompromised() { +        return mStateCompromised; +    } + +    int getStatus() { +        return mStatus; +    } +} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e41a09ef672e..a1989e51ee51 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -57,6 +57,7 @@ import android.net.ConnectivityManager;  import android.net.ConnectivityManager.PacketKeepalive;  import android.net.IConnectivityManager;  import android.net.IIpConnectivityMetrics; +import android.net.INetd;  import android.net.INetdEventCallback;  import android.net.INetworkManagementEventObserver;  import android.net.INetworkPolicyListener; @@ -88,6 +89,7 @@ import android.net.metrics.IpConnectivityLog;  import android.net.metrics.NetworkEvent;  import android.net.netlink.InetDiagMessage;  import android.net.util.MultinetworkPolicyTracker; +import android.net.util.NetdService;  import android.os.Binder;  import android.os.Build;  import android.os.Bundle; @@ -259,7 +261,8 @@ public class ConnectivityService extends IConnectivityManager.Stub      // 0 is full bad, 100 is full good      private int mDefaultInetConditionPublished = 0; -    private INetworkManagementService mNetd; +    private INetworkManagementService mNMS; +    private INetd mNetd;      private INetworkStatsService mStatsService;      private INetworkPolicyManager mPolicyManager;      private NetworkPolicyManagerInternal mPolicyManagerInternal; @@ -759,7 +762,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);          mContext = checkNotNull(context, "missing Context"); -        mNetd = checkNotNull(netManager, "missing INetworkManagementService"); +        mNMS = checkNotNull(netManager, "missing INetworkManagementService");          mStatsService = checkNotNull(statsService, "missing INetworkStatsService");          mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");          mPolicyManagerInternal = checkNotNull( @@ -767,6 +770,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                  "missing NetworkPolicyManagerInternal");          mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED); +        mNetd = NetdService.getInstance();          mKeyStore = KeyStore.getInstance();          mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -849,7 +853,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          mTethering = makeTethering(); -        mPermissionMonitor = new PermissionMonitor(mContext, mNetd); +        mPermissionMonitor = new PermissionMonitor(mContext, mNMS);          //set up the listener for user state for creating user VPNs          IntentFilter intentFilter = new IntentFilter(); @@ -864,8 +868,8 @@ public class ConnectivityService extends IConnectivityManager.Stub                  new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);          try { -            mNetd.registerObserver(mTethering); -            mNetd.registerObserver(mDataActivityObserver); +            mNMS.registerObserver(mTethering); +            mNMS.registerObserver(mDataActivityObserver);          } catch (RemoteException e) {              loge("Error registering observer :" + e);          } @@ -896,7 +900,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler); -        mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties); +        mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);          registerPrivateDnsSettingsCallbacks();      } @@ -912,7 +916,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                  return mDefaultRequest;              }          }; -        return new Tethering(mContext, mNetd, mStatsService, mPolicyManager, +        return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,                  IoThread.get().getLooper(), new MockableSystemProperties(),                  deps);      } @@ -1476,6 +1480,20 @@ public class ConnectivityService extends IConnectivityManager.Stub      };      /** +     * Ensures that the system cannot call a particular method. +     */ +    private boolean disallowedBecauseSystemCaller() { +        // TODO: start throwing a SecurityException when GnssLocationProvider stops calling +        // requestRouteToHost. +        if (isSystem(Binder.getCallingUid())) { +            log("This method exists only for app backwards compatibility" +                    + " and must not be called by system services."); +            return true; +        } +        return false; +    } + +    /**       * Ensure that a network route exists to deliver traffic to the specified       * host via the specified network interface.       * @param networkType the type of the network over which traffic to the @@ -1486,6 +1504,9 @@ public class ConnectivityService extends IConnectivityManager.Stub       */      @Override      public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { +        if (disallowedBecauseSystemCaller()) { +            return false; +        }          enforceChangePermission();          if (mProtectedNetworks.contains(networkType)) {              enforceConnectivityInternalPermission(); @@ -1563,7 +1584,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          if (DBG) log("Adding legacy route " + bestRoute +                  " for UID/PID " + uid + "/" + Binder.getCallingPid());          try { -            mNetd.addLegacyRouteForNetId(netId, bestRoute, uid); +            mNMS.addLegacyRouteForNetId(netId, bestRoute, uid);          } catch (Exception e) {              // never crash - catch them all              if (DBG) loge("Exception trying to add a route: " + e); @@ -1853,7 +1874,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {              try { -                mNetd.addIdleTimer(iface, timeout, type); +                mNMS.addIdleTimer(iface, timeout, type);              } catch (Exception e) {                  // You shall not crash!                  loge("Exception in setupDataActivityTracking " + e); @@ -1872,7 +1893,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                                caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {              try {                  // the call fails silently if no idle timer setup for this interface -                mNetd.removeIdleTimer(iface); +                mNMS.removeIdleTimer(iface);              } catch (Exception e) {                  loge("Exception in removeDataActivityTracking " + e);              } @@ -1880,6 +1901,18 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      /** +     * Update data activity tracking when network state is updated. +     */ +    private void updateDataActivityTracking(NetworkAgentInfo newNetwork, +            NetworkAgentInfo oldNetwork) { +        if (newNetwork != null) { +            setupDataActivityTracking(newNetwork); +        } +        if (oldNetwork != null) { +            removeDataActivityTracking(oldNetwork); +        } +    } +    /**       * Reads the network specific MTU size from resources.       * and set it on it's iface.       */ @@ -1907,7 +1940,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          try {              if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); -            mNetd.setMtu(iface, mtu); +            mNMS.setMtu(iface, mtu);          } catch (Exception e) {              Slog.e(TAG, "exception in setMtu()" + e);          } @@ -2561,7 +2594,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          }          nai.clearLingerState();          if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) { -            removeDataActivityTracking(nai); +            updateDataActivityTracking(null /* newNetwork */, nai);              notifyLockdownVpn(nai);              ensureNetworkTransitionWakelock(nai.name());          } @@ -2581,7 +2614,7 @@ public class ConnectivityService extends IConnectivityManager.Stub              // NetworkFactories, so network traffic isn't interrupted for an unnecessarily              // long time.              try { -                mNetd.removeNetwork(nai.network.netId); +                mNMS.removeNetwork(nai.network.netId);              } catch (Exception e) {                  loge("Exception removing network: " + e);              } @@ -2779,20 +2812,6 @@ public class ConnectivityService extends IConnectivityManager.Stub                  }              } -            // TODO: remove this code once we know that the Slog.wtf is never hit. -            // -            // Find all networks that are satisfying this request and remove the request -            // from their request lists. -            // TODO - it's my understanding that for a request there is only a single -            // network satisfying it, so this loop is wasteful -            for (NetworkAgentInfo otherNai : mNetworkAgentInfos.values()) { -                if (otherNai.isSatisfyingRequest(nri.request.requestId) && otherNai != nai) { -                    Slog.wtf(TAG, "Request " + nri.request + " satisfied by " + -                            otherNai.name() + ", but mNetworkAgentInfos says " + -                            (nai != null ? nai.name() : "null")); -                } -            } -              // Maintain the illusion.  When this request arrived, we might have pretended              // that a network connected to serve it, even though the network was already              // connected.  Now that this request has gone away, we might have to pretend @@ -3760,7 +3779,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                      Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");                      return false;                  } -                setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile)); +                setLockdownTracker(new LockdownVpnTracker(mContext, mNMS, this, vpn, profile));              } else {                  setLockdownTracker(null);              } @@ -4015,7 +4034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                  loge("Starting user already has a VPN");                  return;              } -            userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId); +            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId);              mVpns.put(userId, userVpn);              if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {                  updateLockdownVpn(); @@ -4632,7 +4651,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          mDnsManager.updatePrivateDnsStatus(netId, newLp);          // Start or stop clat accordingly to network state. -        networkAgent.updateClat(mNetd); +        networkAgent.updateClat(mNMS);          if (isDefaultNetwork(networkAgent)) {              handleApplyDefaultProxy(newLp.getHttpProxy());          } else { @@ -4671,9 +4690,9 @@ public class ConnectivityService extends IConnectivityManager.Stub          final String prefix = "iface:" + iface;          try {              if (add) { -                mNetd.getNetdService().wakeupAddInterface(iface, prefix, mark, mask); +                mNetd.wakeupAddInterface(iface, prefix, mark, mask);              } else { -                mNetd.getNetdService().wakeupDelInterface(iface, prefix, mark, mask); +                mNetd.wakeupDelInterface(iface, prefix, mark, mask);              }          } catch (Exception e) {              loge("Exception modifying wakeup packet monitoring: " + e); @@ -4689,7 +4708,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          for (String iface : interfaceDiff.added) {              try {                  if (DBG) log("Adding iface " + iface + " to network " + netId); -                mNetd.addInterfaceToNetwork(iface, netId); +                mNMS.addInterfaceToNetwork(iface, netId);                  wakeupModifyInterface(iface, caps, true);              } catch (Exception e) {                  loge("Exception adding interface: " + e); @@ -4699,7 +4718,7 @@ public class ConnectivityService extends IConnectivityManager.Stub              try {                  if (DBG) log("Removing iface " + iface + " from network " + netId);                  wakeupModifyInterface(iface, caps, false); -                mNetd.removeInterfaceFromNetwork(iface, netId); +                mNMS.removeInterfaceFromNetwork(iface, netId);              } catch (Exception e) {                  loge("Exception removing interface: " + e);              } @@ -4723,7 +4742,7 @@ public class ConnectivityService extends IConnectivityManager.Stub              if (route.hasGateway()) continue;              if (VDBG) log("Adding Route [" + route + "] to network " + netId);              try { -                mNetd.addRoute(netId, route); +                mNMS.addRoute(netId, route);              } catch (Exception e) {                  if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {                      loge("Exception in addRoute for non-gateway: " + e); @@ -4734,7 +4753,7 @@ public class ConnectivityService extends IConnectivityManager.Stub              if (route.hasGateway() == false) continue;              if (VDBG) log("Adding Route [" + route + "] to network " + netId);              try { -                mNetd.addRoute(netId, route); +                mNMS.addRoute(netId, route);              } catch (Exception e) {                  if ((route.getGateway() instanceof Inet4Address) || VDBG) {                      loge("Exception in addRoute for gateway: " + e); @@ -4745,7 +4764,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          for (RouteInfo route : routeDiff.removed) {              if (VDBG) log("Removing Route [" + route + "] from network " + netId);              try { -                mNetd.removeRoute(netId, route); +                mNMS.removeRoute(netId, route);              } catch (Exception e) {                  loge("Exception in removeRoute: " + e);              } @@ -4857,7 +4876,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          final String newPermission = getNetworkPermission(newNc);          if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {              try { -                mNetd.setNetworkPermission(nai.network.netId, newPermission); +                mNMS.setNetworkPermission(nai.network.netId, newPermission);              } catch (RemoteException e) {                  loge("Exception in setNetworkPermission: " + e);              } @@ -4917,12 +4936,12 @@ public class ConnectivityService extends IConnectivityManager.Stub              if (!newRanges.isEmpty()) {                  final UidRange[] addedRangesArray = new UidRange[newRanges.size()];                  newRanges.toArray(addedRangesArray); -                mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray); +                mNMS.addVpnUidRanges(nai.network.netId, addedRangesArray);              }              if (!prevRanges.isEmpty()) {                  final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];                  prevRanges.toArray(removedRangesArray); -                mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray); +                mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);              }          } catch (Exception e) {              // Never crash! @@ -5091,9 +5110,9 @@ public class ConnectivityService extends IConnectivityManager.Stub      private void makeDefault(NetworkAgentInfo newNetwork) {          if (DBG) log("Switching to new default network: " + newNetwork); -        setupDataActivityTracking(newNetwork); +          try { -            mNetd.setDefaultNetId(newNetwork.network.netId); +            mNMS.setDefaultNetId(newNetwork.network.netId);          } catch (Exception e) {              loge("Exception setting default network :" + e);          } @@ -5266,6 +5285,7 @@ public class ConnectivityService extends IConnectivityManager.Stub              }          }          if (isNewDefault) { +            updateDataActivityTracking(newNetwork, oldDefaultNetwork);              // Notify system services that this network is up.              makeDefault(newNetwork);              // Log 0 -> X and Y -> X default network transitions, where X is the new default. @@ -5488,12 +5508,12 @@ public class ConnectivityService extends IConnectivityManager.Stub              try {                  // This should never fail.  Specifying an already in use NetID will cause failure.                  if (networkAgent.isVPN()) { -                    mNetd.createVirtualNetwork(networkAgent.network.netId, +                    mNMS.createVirtualNetwork(networkAgent.network.netId,                              !networkAgent.linkProperties.getDnsServers().isEmpty(),                              (networkAgent.networkMisc == null ||                                  !networkAgent.networkMisc.allowBypass));                  } else { -                    mNetd.createPhysicalNetwork(networkAgent.network.netId, +                    mNMS.createPhysicalNetwork(networkAgent.network.netId,                              getNetworkPermission(networkAgent.networkCapabilities));                  }              } catch (Exception e) { diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java index 4f0e17055769..96ce6a4ee6a4 100644 --- a/services/core/java/com/android/server/LooperStatsService.java +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -129,7 +129,12 @@ public class LooperStatsService extends Binder {      }      private void setSamplingInterval(int samplingInterval) { -        mStats.setSamplingInterval(samplingInterval); +        if (samplingInterval > 0) { +            mStats.setSamplingInterval(samplingInterval); +        } else { +            Slog.w(TAG, "Ignored invalid sampling interval (value must be positive): " +                    + samplingInterval); +        }      }      /** diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1d163eed00a4..de930f794e50 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -161,6 +161,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub      private static final int MAX_UID_RANGES_PER_COMMAND = 10; +    private static final  String[] EMPTY_STRING_ARRAY = new String[0]; +      /**       * Name representing {@link #setGlobalAlert(long)} limit when delivered to       * {@link INetworkManagementEventObserver#limitReached(String, String)}. @@ -1234,18 +1236,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub      @Override      public void startTethering(String[] dhcpRange) {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); -        // cmd is "tether start first_start first_stop second_start second_stop ..."          // an odd number of addrs will fail -        final Command cmd = new Command("tether", "start"); -        for (String d : dhcpRange) { -            cmd.appendArg(d); -        } -          try { -            mConnector.execute(cmd); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            mNetdService.tetherStart(dhcpRange); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }      } @@ -1253,9 +1249,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub      public void stopTethering() {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          try { -            mConnector.execute("tether", "stop"); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            mNetdService.tetherStop(); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }      } @@ -1263,25 +1259,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub      public boolean isTetheringStarted() {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); -        final NativeDaemonEvent event;          try { -            event = mConnector.execute("tether", "status"); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            final boolean isEnabled = mNetdService.tetherIsEnabled(); +            return isEnabled; +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          } - -        // 210 Tethering services started -        event.checkCode(TetherStatusResult); -        return event.getMessage().endsWith("started");      }      @Override      public void tetherInterface(String iface) {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          try { -            mConnector.execute("tether", "interface", "add", iface); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            mNetdService.tetherInterfaceAdd(iface); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }          List<RouteInfo> routes = new ArrayList<>();          // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it @@ -1294,9 +1286,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub      public void untetherInterface(String iface) {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          try { -            mConnector.execute("tether", "interface", "remove", iface); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            mNetdService.tetherInterfaceRemove(iface); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          } finally {              removeInterfaceFromLocalNetwork(iface);          } @@ -1306,11 +1298,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub      public String[] listTetheredInterfaces() {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          try { -            return NativeDaemonEvent.filterMessageList( -                    mConnector.executeForList("tether", "interface", "list"), -                    TetherInterfaceListResult); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            final List<String> result = mNetdService.tetherInterfaceList(); +            return result.toArray(EMPTY_STRING_ARRAY); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }      } @@ -1319,16 +1310,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET; -        final Command cmd = new Command("tether", "dns", "set", netId); - -        for (String s : dns) { -            cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress()); -        }          try { -            mConnector.execute(cmd); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            mNetdService.tetherDnsSet(netId, dns); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }      } @@ -1336,10 +1322,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub      public String[] getDnsForwarders() {          mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);          try { -            return NativeDaemonEvent.filterMessageList( -                    mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult); -        } catch (NativeDaemonConnectorException e) { -            throw e.rethrowAsParcelableException(); +            final List<String> result = mNetdService.tetherDnsList(); +            return result.toArray(EMPTY_STRING_ARRAY); +        } catch (RemoteException | ServiceSpecificException e) { +            throw new IllegalStateException(e);          }      } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d505a77c9192..21f54dd33d3e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -329,6 +329,12 @@ class StorageManagerService extends IStorageManager.Stub      @GuardedBy("mPackagesLock")      private final SparseArray<String> mSandboxIds = new SparseArray<>(); +    /** +     * List of volumes visible to any user. +     * TODO: may be have a map of userId -> volumes? +     */ +    private final CopyOnWriteArrayList<VolumeInfo> mVisibleVols = new CopyOnWriteArrayList<>(); +      private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;      /** Holding lock for AppFuse business */ @@ -623,16 +629,12 @@ class StorageManagerService extends IStorageManager.Stub                          Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");                          break;                      } -                    try { -                        mVold.mount(vol.id, vol.mountFlags, vol.mountUserId); -                    } catch (Exception e) { -                        Slog.wtf(TAG, e); -                    } +                    mount(vol);                      break;                  }                  case H_VOLUME_UNMOUNT: {                      final VolumeInfo vol = (VolumeInfo) msg.obj; -                    unmount(vol.getId()); +                    unmount(vol);                      break;                  }                  case H_VOLUME_BROADCAST: { @@ -869,6 +871,8 @@ class StorageManagerService extends IStorageManager.Stub                  addInternalVolumeLocked();              } +            mVisibleVols.clear(); +              try {                  mVold.reset(); @@ -1466,7 +1470,7 @@ class StorageManagerService extends IStorageManager.Stub                      = mContext.getPackageManager().getInstalledApplicationsAsUser(                              PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);              synchronized (mPackagesLock) { -                final ArraySet<String> userPackages = getPackagesForUserPL(userId); +                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);                  for (int i = appInfos.size() - 1; i >= 0; --i) {                      if (appInfos.get(i).isInstantApp()) {                          continue; @@ -1523,7 +1527,7 @@ class StorageManagerService extends IStorageManager.Stub      }      @GuardedBy("mPackagesLock") -    private ArraySet<String> getPackagesForUserPL(int userId) { +    private ArraySet<String> getAvailablePackagesForUserPL(int userId) {          ArraySet<String> userPackages = mPackages.get(userId);          if (userPackages == null) {              userPackages = new ArraySet<>(); @@ -1535,8 +1539,24 @@ class StorageManagerService extends IStorageManager.Stub      private String[] getPackagesArrayForUser(int userId) {          if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING; +        final ArraySet<String> userPackages;          synchronized (mPackagesLock) { -            return getPackagesForUserPL(userId).toArray(new String[0]); +            userPackages = getAvailablePackagesForUserPL(userId); +            if (!userPackages.isEmpty()) { +                return userPackages.toArray(new String[0]); +            } +        } +        final List<ApplicationInfo> appInfos = +                mContext.getPackageManager().getInstalledApplicationsAsUser( +                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); +        synchronized (mPackagesLock) { +            for (int i = appInfos.size() - 1; i >= 0; --i) { +                if (appInfos.get(i).isInstantApp()) { +                    continue; +                } +                userPackages.add(appInfos.get(i).packageName); +            } +            return userPackages.toArray(new String[0]);          }      } @@ -1747,8 +1767,15 @@ class StorageManagerService extends IStorageManager.Stub          if (isMountDisallowed(vol)) {              throw new SecurityException("Mounting " + volId + " restricted by policy");          } +        mount(vol); +    } + +    private void mount(VolumeInfo vol) {          try {              mVold.mount(vol.id, vol.mountFlags, vol.mountUserId); +            if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) { +                mVisibleVols.add(vol); +            }          } catch (Exception e) {              Slog.wtf(TAG, e);          } @@ -1759,8 +1786,15 @@ class StorageManagerService extends IStorageManager.Stub          enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);          final VolumeInfo vol = findVolumeByIdOrThrow(volId); +        unmount(vol); +    } + +    private void unmount(VolumeInfo vol) {          try {              mVold.unmount(vol.id); +            if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) { +                mVisibleVols.remove(vol); +            }          } catch (Exception e) {              Slog.wtf(TAG, e);          } @@ -3596,6 +3630,14 @@ class StorageManagerService extends IStorageManager.Stub              pw.decreaseIndent();              pw.println(); +            pw.println("mVisibleVols:"); +            pw.increaseIndent(); +            for (int i = 0; i < mVisibleVols.size(); i++) { +                mVisibleVols.get(i).dump(pw); +            } +            pw.decreaseIndent(); + +            pw.println();              pw.println("Primary storage UUID: " + mPrimaryStorageUuid);              final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();              if (pair == null) { @@ -3716,7 +3758,7 @@ class StorageManagerService extends IStorageManager.Stub                  int userId) {              final String sandboxId;              synchronized (mPackagesLock) { -                final ArraySet<String> userPackages = getPackagesForUserPL(userId); +                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);                  // If userPackages is empty, it means the user is not started yet, so no need to                  // do anything now.                  if (userPackages.isEmpty() || userPackages.contains(packageName)) { @@ -3734,5 +3776,29 @@ class StorageManagerService extends IStorageManager.Stub                  Slog.wtf(TAG, e);              }          } + +        @Override +        public String[] getVisibleVolumesForUser(int userId) { +            final ArrayList<String> visibleVolsForUser = new ArrayList<>(); +            for (int i = mVisibleVols.size() - 1; i >= 0; --i) { +                final VolumeInfo vol = mVisibleVols.get(i); +                if (vol.isVisibleForUser(userId)) { +                    visibleVolsForUser.add(getVolumeLabel(vol)); +                } +            } +            return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]); +        } + +        private String getVolumeLabel(VolumeInfo vol) { +            // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold +            switch (vol.getType()) { +                case VolumeInfo.TYPE_EMULATED: +                    return "emulated"; +                case VolumeInfo.TYPE_PUBLIC: +                    return vol.fsUuid == null ? vol.id : vol.fsUuid; +                default: +                    return null; +            } +        }      }  } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 98b88cb557af..fb8894b48411 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -213,6 +213,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {      private PhoneCapability mPhoneCapability = null; +    private int mPreferredDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; +      private final LocalLog mLocalLog = new LocalLog(100);      private PreciseDataConnectionState mPreciseDataConnectionState = @@ -752,6 +754,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {                              remove(r.binder);                          }                      } +                    if ((events & PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE) != 0) { +                        try { +                            r.callback.onPreferredDataSubIdChanged(mPreferredDataSubId); +                        } catch (RemoteException ex) { +                            remove(r.binder); +                        } +                    }                  }              }          } else { @@ -1573,6 +1582,31 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {          }      } +    public void notifyPreferredDataSubIdChanged(int preferredSubId) { +        if (!checkNotifyPermission("notifyPreferredDataSubIdChanged()")) { +            return; +        } + +        if (VDBG) { +            log("notifyPreferredDataSubIdChanged: preferredSubId=" + preferredSubId); +        } + +        synchronized (mRecords) { +            mPreferredDataSubId = preferredSubId; + +            for (Record r : mRecords) { +                if (r.matchPhoneStateListenerEvent( +                        PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE)) { +                    try { +                        r.callback.onPreferredDataSubIdChanged(preferredSubId); +                    } catch (RemoteException ex) { +                        mRemoveList.add(r.binder); +                    } +                } +            } +            handleRemoveListLocked(); +        } +    }      @Override      public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { @@ -1610,6 +1644,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {              pw.println("mBackgroundCallState=" + mBackgroundCallState);              pw.println("mVoLteServiceState=" + mVoLteServiceState);              pw.println("mPhoneCapability=" + mPhoneCapability); +            pw.println("mPreferredDataSubId=" + mPreferredDataSubId);              pw.decreaseIndent(); @@ -1647,6 +1682,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {          intent.putExtras(data);          // Pass the subscription along with the intent.          intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); +        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);          intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);          mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);      } @@ -1701,6 +1737,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {          if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {              intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);              intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); +            intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);          }          // If the phoneId is invalid, the broadcast is for overall call state.          if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) { diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 6d69fcd3e453..0b836f0d186f 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -94,7 +94,7 @@ public class Watchdog extends Thread {          "media.metrics", // system/bin/mediametrics          "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service          "com.android.bluetooth",  // Bluetooth service -        "statsd",  // Stats daemon +        "/system/bin/statsd",  // Stats daemon      };      public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList( diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 510d333355a3..461d39d0a29a 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -629,7 +629,7 @@ public final class ActiveServices {                  return false;              } -            IIntentSender target = mAm.getIntentSenderLocked( +            IIntentSender target = mAm.mPendingIntentController.getIntentSender(                      ActivityManager.INTENT_SENDER_SERVICE, callingPackage,                      callingUid, userId, null, null, 0, new Intent[]{service},                      new String[]{service.resolveType(mAm.mContext.getContentResolver())}, diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 01421c7e65c2..fab967c01086 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -890,6 +890,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>          mRemoved = true;          releaseSelfIfNeeded(); + +        mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId);      }      private void releaseSelfIfNeeded() { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8c7fc849b79e..aa14da0ad70a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -134,7 +134,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;  import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;  import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;  import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;  import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -369,7 +368,6 @@ import java.io.InputStreamReader;  import java.io.PrintWriter;  import java.io.StringWriter;  import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference;  import java.text.DateFormat;  import java.text.SimpleDateFormat;  import java.util.ArrayList; @@ -417,7 +415,6 @@ public class ActivityManagerService extends IActivityManager.Stub      private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;      private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;      private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS; -    private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;      // Mock "pretend we're idle now" broadcast action to the job scheduler; declared      // here so that while the job scheduler can depend on AMS, the other way around @@ -563,6 +560,7 @@ public class ActivityManagerService extends IActivityManager.Stub      String mDeviceOwnerName;      final UserController mUserController; +    final PendingIntentController mPendingIntentController;      final AppErrors mAppErrors; @@ -821,12 +819,6 @@ public class ActivityManagerService extends IActivityManager.Stub      final SparseArray<UidRecord> mValidateUids = new SparseArray<>();      /** -     * Set of IntentSenderRecord objects that are currently active. -     */ -    final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords -            = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>(); - -    /**       * Fingerprints (hashCode()) of stack traces that we've       * already logged DropBox entries for.  Guarded by itself.  If       * something (rogue user app) forces this over @@ -1426,7 +1418,6 @@ public class ActivityManagerService extends IActivityManager.Stub      static final int UPDATE_TIME_ZONE = 13;      static final int PROC_START_TIMEOUT_MSG = 20;      static final int KILL_APPLICATION_MSG = 22; -    static final int FINALIZE_PENDING_INTENT_MSG = 23;      static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;      static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27;      static final int CLEAR_DNS_CACHE_MSG = 28; @@ -1445,7 +1436,6 @@ public class ActivityManagerService extends IActivityManager.Stub      static final int IDLE_UIDS_MSG = 58;      static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;      static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; -    static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;      static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;      static final int SERVICE_FOREGROUND_CRASH_MSG = 69;      static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; @@ -1644,21 +1634,6 @@ public class ActivityManagerService extends IActivityManager.Stub                  mServices.serviceForegroundCrash(                      (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));              } break; -            case DISPATCH_PENDING_INTENT_CANCEL_MSG: { -                RemoteCallbackList<IResultReceiver> callbacks -                        = (RemoteCallbackList<IResultReceiver>)msg.obj; -                int N = callbacks.beginBroadcast(); -                for (int i = 0; i < N; i++) { -                    try { -                        callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); -                    } catch (RemoteException e) { -                    } -                } -                callbacks.finishBroadcast(); -                // We have to clean up the RemoteCallbackList here, because otherwise it will -                // needlessly hold the enclosed callbacks until the remote process dies. -                callbacks.kill(); -            } break;              case UPDATE_TIME_ZONE: {                  synchronized (ActivityManagerService.this) {                      for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { @@ -1738,9 +1713,6 @@ public class ActivityManagerService extends IActivityManager.Stub                              false, userId, reason);                  }              } break; -            case FINALIZE_PENDING_INTENT_MSG: { -                ((PendingIntentRecord)msg.obj).completeFinalize(); -            } break;              case CHECK_EXCESSIVE_POWER_USE_MSG: {                  synchronized (ActivityManagerService.this) {                      checkExcessivePowerUsageLocked(); @@ -2354,6 +2326,7 @@ public class ActivityManagerService extends IActivityManager.Stub          mSystemThread = null;          mUiHandler = injector.getUiHandler(null);          mUserController = null; +        mPendingIntentController = null;          mProcStartHandlerThread = null;          mProcStartHandler = null;          mHiddenApiBlacklist = null; @@ -2407,7 +2380,8 @@ public class ActivityManagerService extends IActivityManager.Stub          final File systemDir = SystemServiceManager.ensureSystemDir();          // TODO: Move creation of battery stats service outside of activity manager service. -        mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler); +        mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, +                BackgroundThread.get().getHandler());          mBatteryStatsService.getActiveStatistics().readLocked();          mBatteryStatsService.scheduleWriteToDisk();          mOnBattery = DEBUG_POWER ? true @@ -2423,6 +2397,9 @@ public class ActivityManagerService extends IActivityManager.Stub          mUserController = new UserController(this); +        mPendingIntentController = new PendingIntentController( +                mHandlerThread.getLooper(), mUserController); +          GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",              ConfigurationInfo.GL_ES_VERSION_UNDEFINED); @@ -2508,6 +2485,7 @@ public class ActivityManagerService extends IActivityManager.Stub          LocalServices.addService(ActivityManagerInternal.class, new LocalService());          mActivityTaskManager.onActivityManagerInternalAdded();          mUgmInternal.onActivityManagerInternalAdded(); +        mPendingIntentController.onActivityManagerInternalAdded();          // Wait for the synchronized block started in mProcessCpuThread,          // so that any other access to mProcessCpuTracker from main thread          // will be blocked during mProcessCpuTracker initialization. @@ -3559,6 +3537,9 @@ public class ActivityManagerService extends IActivityManager.Stub              String seInfo, String requiredAbi, String instructionSet, String invokeWith,              long startTime) {          try { +            final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); +            final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class) +                    .getVisibleVolumesForUser(UserHandle.getUserId(uid));              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +                      app.processName);              checkTime(startTime, "startProcess: asking zygote to start proc"); @@ -3568,12 +3549,14 @@ public class ActivityManagerService extends IActivityManager.Stub                          app.processName, uid, uid, gids, runtimeFlags, mountExternal,                          app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,                          app.info.dataDir, null, app.info.packageName, +                        packageNames, visibleVolIds,                          new String[] {PROC_START_SEQ_IDENT + app.startSeq});              } else {                  startResult = Process.start(entryPoint,                          app.processName, uid, uid, gids, runtimeFlags, mountExternal,                          app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,                          app.info.dataDir, invokeWith, app.info.packageName, +                        packageNames, visibleVolIds,                          new String[] {PROC_START_SEQ_IDENT + app.startSeq});              }              checkTime(startTime, "startProcess: returned from zygote!"); @@ -4219,7 +4202,6 @@ public class ActivityManagerService extends IActivityManager.Stub      private final void handleAppDiedLocked(ProcessRecord app,              boolean restarting, boolean allowRestart) {          int pid = app.pid; -        final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities;          boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,                  false /*replacingPid*/);          if (!kept && !restarting) { @@ -4260,18 +4242,6 @@ public class ActivityManagerService extends IActivityManager.Stub              mWindowManager.continueSurfaceLayout();          } -        // TODO (b/67683350) -        // When an app process is removed, activities from the process may be relaunched. In the -        // case of forceStopPackageLocked the activities are finished before any window is drawn, -        // and the launch time is not cleared. This will be incorrectly used to calculate launch -        // time for the next launched activity launched in the same windowing mode. -        if (clearLaunchStartTime) { -            final LaunchTimeTracker.Entry entry = mStackSupervisor -                    .getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode()); -            if (entry != null) { -                entry.mLaunchStartTime = 0; -            } -        }      }      private final int getLRURecordIndexForAppLocked(IApplicationThread thread) { @@ -5511,55 +5481,8 @@ public class ActivityManagerService extends IActivityManager.Stub          }          if (packageName == null || uninstalling) { -            // Remove pending intents.  For now we only do this when force -            // stopping users, because we have some problems when doing this -            // for packages -- app widgets are not currently cleaned up for -            // such packages, so they can be left with bad pending intents. -            if (mIntentSenderRecords.size() > 0) { -                Iterator<WeakReference<PendingIntentRecord>> it -                        = mIntentSenderRecords.values().iterator(); -                while (it.hasNext()) { -                    WeakReference<PendingIntentRecord> wpir = it.next(); -                    if (wpir == null) { -                        it.remove(); -                        continue; -                    } -                    PendingIntentRecord pir = wpir.get(); -                    if (pir == null) { -                        it.remove(); -                        continue; -                    } -                    if (packageName == null) { -                        // Stopping user, remove all objects for the user. -                        if (pir.key.userId != userId) { -                            // Not the same user, skip it. -                            continue; -                        } -                    } else { -                        if (UserHandle.getAppId(pir.uid) != appId) { -                            // Different app id, skip it. -                            continue; -                        } -                        if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { -                            // Different user, skip it. -                            continue; -                        } -                        if (!pir.key.packageName.equals(packageName)) { -                            // Different package, skip it. -                            continue; -                        } -                    } -                    if (!doit) { -                        return true; -                    } -                    didSomething = true; -                    it.remove(); -                    makeIntentSenderCanceledLocked(pir); -                    if (pir.key.activity != null && pir.key.activity.pendingResults != null) { -                        pir.key.activity.pendingResults.remove(pir.ref); -                    } -                } -            } +            didSomething |= mPendingIntentController.removePendingIntentsForPackage( +                    packageName, userId, appId, doit);          }          if (doit) { @@ -6342,90 +6265,19 @@ public class ActivityManagerService extends IActivityManager.Stub                      }                  } -                return getIntentSenderLocked(type, packageName, callingUid, userId, -                        token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); - +                if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { +                    return mAtmInternal.getIntentSender(type, packageName, callingUid, userId, +                            token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); +                } +                return mPendingIntentController.getIntentSender(type, packageName, callingUid, +                        userId, token, resultWho, requestCode, intents, resolvedTypes, flags, +                        bOptions);              } catch (RemoteException e) {                  throw new SecurityException(e);              }          }      } -    IIntentSender getIntentSenderLocked(int type, String packageName, -            int callingUid, int userId, IBinder token, String resultWho, -            int requestCode, Intent[] intents, String[] resolvedTypes, int flags, -            Bundle bOptions) { -        if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid); -        ActivityRecord activity = null; -        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { -            activity = ActivityRecord.isInStackLocked(token); -            if (activity == null) { -                Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); -                return null; -            } -            if (activity.finishing) { -                Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); -                return null; -            } -        } - -        // We're going to be splicing together extras before sending, so we're -        // okay poking into any contained extras. -        if (intents != null) { -            for (int i = 0; i < intents.length; i++) { -                intents[i].setDefusable(true); -            } -        } -        Bundle.setDefusable(bOptions, true); - -        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; -        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; -        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; -        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT -                |PendingIntent.FLAG_UPDATE_CURRENT); - -        PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, -                resultWho, requestCode, intents, resolvedTypes, flags, -                SafeActivityOptions.fromBundle(bOptions), userId); -        WeakReference<PendingIntentRecord> ref; -        ref = mIntentSenderRecords.get(key); -        PendingIntentRecord rec = ref != null ? ref.get() : null; -        if (rec != null) { -            if (!cancelCurrent) { -                if (updateCurrent) { -                    if (rec.key.requestIntent != null) { -                        rec.key.requestIntent.replaceExtras(intents != null ? -                                intents[intents.length - 1] : null); -                    } -                    if (intents != null) { -                        intents[intents.length-1] = rec.key.requestIntent; -                        rec.key.allIntents = intents; -                        rec.key.allResolvedTypes = resolvedTypes; -                    } else { -                        rec.key.allIntents = null; -                        rec.key.allResolvedTypes = null; -                    } -                } -                return rec; -            } -            makeIntentSenderCanceledLocked(rec); -            mIntentSenderRecords.remove(key); -        } -        if (noCreate) { -            return rec; -        } -        rec = new PendingIntentRecord(this, key, callingUid); -        mIntentSenderRecords.put(key, rec.ref); -        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { -            if (activity.pendingResults == null) { -                activity.pendingResults -                        = new HashSet<WeakReference<PendingIntentRecord>>(); -            } -            activity.pendingResults.add(rec.ref); -        } -        return rec; -    } -      @Override      public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,              Intent intent, String resolvedType, @@ -6465,44 +6317,7 @@ public class ActivityManagerService extends IActivityManager.Stub      @Override      public void cancelIntentSender(IIntentSender sender) { -        if (!(sender instanceof PendingIntentRecord)) { -            return; -        } -        synchronized(this) { -            PendingIntentRecord rec = (PendingIntentRecord)sender; -            try { -                final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, -                        MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); -                if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { -                    String msg = "Permission Denial: cancelIntentSender() from pid=" -                        + Binder.getCallingPid() -                        + ", uid=" + Binder.getCallingUid() -                        + " is not allowed to cancel package " -                        + rec.key.packageName; -                    Slog.w(TAG, msg); -                    throw new SecurityException(msg); -                } -            } catch (RemoteException e) { -                throw new SecurityException(e); -            } -            cancelIntentSenderLocked(rec, true); -        } -    } - -    void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) { -        makeIntentSenderCanceledLocked(rec); -        mIntentSenderRecords.remove(rec.key); -        if (cleanActivity && rec.key.activity != null) { -            rec.key.activity.pendingResults.remove(rec.ref); -        } -    } - -    void makeIntentSenderCanceledLocked(PendingIntentRecord rec) { -        rec.canceled = true; -        RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); -        if (callbacks != null) { -            mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget(); -        } +        mPendingIntentController.cancelIntentSender(sender);      }      @Override @@ -7813,7 +7628,23 @@ public class ActivityManagerService extends IActivityManager.Stub                  }              } -            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed; +            boolean providerRunning = false; + +            if (cpr != null && cpr.proc != null) { +                providerRunning = !cpr.proc.killed; + +                // Note if killedByAm is also set, this means the provider process has just been +                // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called +                // yet. So we need to call appDiedLocked() here and let it clean up. +                // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see +                // how to test this case.) +                if (cpr.proc.killed && cpr.proc.killedByAm) { +                    checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)"); +                    appDiedLocked(cpr.proc); +                    checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)"); +                } +            } +              if (providerRunning) {                  cpi = cpr.info;                  String msg; @@ -9607,9 +9438,10 @@ public class ActivityManagerService extends IActivityManager.Stub          mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);          if (workSource != null) { -            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag); +            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag, sourcePkg);          } else { -            StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag); +            StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag, +                    sourcePkg);          }      } @@ -10866,7 +10698,7 @@ public class ActivityManagerService extends IActivityManager.Stub                  pw.println("-------------------------------------------------------------------------------");              } -            dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); +            mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage);              pw.println();              if (dumpAll) {                  pw.println("-------------------------------------------------------------------------------"); @@ -11159,7 +10991,7 @@ public class ActivityManagerService extends IActivityManager.Stub                      opti++;                  }                  synchronized (this) { -                    dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage); +                    mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage);                  }              } else if ("processes".equals(cmd) || "p".equals(cmd)) {                  if (opti < args.length) { @@ -12857,61 +12689,6 @@ public class ActivityManagerService extends IActivityManager.Stub          mUgmInternal.dump(pw, dumpAll, dumpPackage);      } -    void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args, -            int opti, boolean dumpAll, String dumpPackage) { -        boolean printed = false; - -        pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); - -        if (mIntentSenderRecords.size() > 0) { -            // Organize these by package name, so they are easier to read. -            final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); -            final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); -            final Iterator<WeakReference<PendingIntentRecord>> it -                    = mIntentSenderRecords.values().iterator(); -            while (it.hasNext()) { -                WeakReference<PendingIntentRecord> ref = it.next(); -                PendingIntentRecord rec = ref != null ? ref.get() : null; -                if (rec == null) { -                    weakRefs.add(ref); -                    continue; -                } -                if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { -                    continue; -                } -                ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); -                if (list == null) { -                    list = new ArrayList<>(); -                    byPackage.put(rec.key.packageName, list); -                } -                list.add(rec); -            } -            for (int i = 0; i < byPackage.size(); i++) { -                ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); -                printed = true; -                pw.print("  * "); pw.print(byPackage.keyAt(i)); -                pw.print(": "); pw.print(intents.size()); pw.println(" items"); -                for (int j = 0; j < intents.size(); j++) { -                    pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); -                    if (dumpAll) { -                        intents.get(j).dump(pw, "      "); -                    } -                } -            } -            if (weakRefs.size() > 0) { -                printed = true; -                pw.println("  * WEAK REFS:"); -                for (int i = 0; i < weakRefs.size(); i++) { -                    pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); -                } -            } -        } - -        if (!printed) { -            pw.println("  (nothing)"); -        } -    } -      private static final int dumpProcessList(PrintWriter pw,              ActivityManagerService service, List list,              String prefix, String normalLabel, String persistentLabel, @@ -15186,24 +14963,6 @@ public class ActivityManagerService extends IActivityManager.Stub          }      } -    ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, -            boolean fgRequired, String callingPackage, int userId) -            throws TransactionTooLargeException { -        synchronized(this) { -            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, -                    "startServiceInPackage: " + service + " type=" + resolvedType); -            final long origId = Binder.clearCallingIdentity(); -            ComponentName res; -            try { -                res = mServices.startServiceLocked(null, service, -                        resolvedType, -1, uid, fgRequired, callingPackage, userId); -            } finally { -                Binder.restoreCallingIdentity(origId); -            } -            return res; -        } -    } -      @Override      public int stopService(IApplicationThread caller, Intent service,              String resolvedType, int userId) { @@ -20892,7 +20651,8 @@ public class ActivityManagerService extends IActivityManager.Stub                                      memoryStat.pgmajfault,                                      memoryStat.rssInBytes,                                      memoryStat.cacheInBytes, -                                    memoryStat.swapInBytes); +                                    memoryStat.swapInBytes, +                                    memoryStat.rssHighWatermarkInBytes);                      processMemoryStates.add(processMemoryState);                  }              } @@ -21091,6 +20851,46 @@ public class ActivityManagerService extends IActivityManager.Stub          public void finishBooting() {              ActivityManagerService.this.finishBooting();          } + +        @Override +        public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, +                long duration, String tag) { +            synchronized (ActivityManagerService.this) { +                ActivityManagerService.this.tempWhitelistForPendingIntentLocked( +                        callerPid, callerUid, targetUid, duration, tag); +            } +        } + +        @Override +        public int broadcastIntentInPackage(String packageName, int uid, Intent intent, +                String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, +                Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, +                boolean sticky, int userId) { +            synchronized (ActivityManagerService.this) { +                return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid, +                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras, +                        requiredPermission, bOptions, serialized, sticky, userId); +            } +        } + +        @Override +        public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, +                boolean fgRequired, String callingPackage, int userId) +                throws TransactionTooLargeException { +            synchronized(ActivityManagerService.this) { +                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, +                        "startServiceInPackage: " + service + " type=" + resolvedType); +                final long origId = Binder.clearCallingIdentity(); +                ComponentName res; +                try { +                    res = mServices.startServiceLocked(null, service, +                            resolvedType, -1, uid, fgRequired, callingPackage, userId); +                } finally { +                    Binder.restoreCallingIdentity(origId); +                } +                return res; +            } +        }      }      /** diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 4bcaf7145e60..40c555f8c2e6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -568,9 +568,6 @@ final class ActivityManagerShellCommand extends ShellCommand {                  if (result.who != null) {                      pw.println("Activity: " + result.who.flattenToShortString());                  } -                if (result.thisTime >= 0) { -                    pw.println("ThisTime: " + result.thisTime); -                }                  if (result.totalTime >= 0) {                      pw.println("TotalTime: " + result.totalTime);                  } diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 78b42f2068ee..18cdb054e648 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -75,6 +75,7 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T  import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;  import static com.android.server.am.MemoryStatUtil.MemoryStat;  import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;  import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT; @@ -89,10 +90,14 @@ import android.os.Handler;  import android.os.Looper;  import android.os.Message;  import android.os.SystemClock; +import android.os.Trace; +import android.util.EventLog; +import android.util.Log;  import android.util.Slog;  import android.util.SparseArray;  import android.util.SparseIntArray;  import android.util.StatsLog; +import android.util.TimeUtils;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.os.BackgroundThread; @@ -100,7 +105,12 @@ import com.android.internal.os.SomeArgs;  import com.android.server.LocalServices;  /** - * Handles logging into Tron. + * Listens to activity launches, transitions, visibility changes and window drawn callbacks to + * determine app launch times and draw delays. Source of truth for activity metrics and provides + * data for Tron, logcat, event logs and {@link android.app.WaitResult}. + * + * Tests: + * atest SystemMetricsFunctionalTests   */  class ActivityMetricsLogger { @@ -115,6 +125,8 @@ class ActivityMetricsLogger {      private static final int WINDOW_STATE_INVALID = -1;      private static final long INVALID_START_TIME = -1; +    private static final int INVALID_DELAY = -1; +    private static final int INVALID_TRANSITION_TYPE = -1;      private static final int MSG_CHECK_VISIBILITY = 0; @@ -143,6 +155,8 @@ class ActivityMetricsLogger {      private final H mHandler;      private ArtManagerInternal mArtManagerInternal; +    private boolean mDrawingTraceActive; +    private final StringBuilder mStringBuilder = new StringBuilder();      private final class H extends Handler { @@ -165,36 +179,56 @@ class ActivityMetricsLogger {          private ActivityRecord launchedActivity;          private int startResult;          private boolean currentTransitionProcessRunning; +        /** Elapsed time from when we launch an activity to when its windows are drawn. */          private int windowsDrawnDelayMs; -        private int startingWindowDelayMs = -1; -        private int bindApplicationDelayMs = -1; +        private int startingWindowDelayMs = INVALID_DELAY; +        private int bindApplicationDelayMs = INVALID_DELAY;          private int reason = APP_TRANSITION_TIMEOUT;          private boolean loggedWindowsDrawn;          private boolean loggedStartingWindowDrawn; +        private boolean launchTraceActive;      } -    private final class WindowingModeTransitionInfoSnapshot { +    final class WindowingModeTransitionInfoSnapshot {          final private ApplicationInfo applicationInfo;          final private WindowProcessController processRecord; -        final private String packageName; -        final private String launchedActivityName; +        final String packageName; +        final String launchedActivityName;          final private String launchedActivityLaunchedFromPackage;          final private String launchedActivityLaunchToken;          final private String launchedActivityAppRecordRequiredAbi; +        final String launchedActivityShortComponentName;          final private String processName;          final private int reason;          final private int startingWindowDelayMs;          final private int bindApplicationDelayMs; -        final private int windowsDrawnDelayMs; -        final private int type; +        final int windowsDrawnDelayMs; +        final int type; +        final int userId; +        /** +         * Elapsed time from when we launch an activity to when the app reported it was +         * fully drawn. If this is not reported then the value is set to INVALID_DELAY. +         */ +        final int windowsFullyDrawnDelayMs; +        final int activityRecordIdHashCode;          private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info) { -            applicationInfo = info.launchedActivity.appInfo; -            packageName = info.launchedActivity.packageName; -            launchedActivityName = info.launchedActivity.info.name; -            launchedActivityLaunchedFromPackage = info.launchedActivity.launchedFromPackage; -            launchedActivityLaunchToken = info.launchedActivity.info.launchToken; -            launchedActivityAppRecordRequiredAbi = info.launchedActivity.app == null +            this(info, info.launchedActivity); +        } + +        private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info, +                ActivityRecord launchedActivity) { +            this(info, launchedActivity, INVALID_DELAY); +        } + +        private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info, +                ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs) { +            applicationInfo = launchedActivity.appInfo; +            packageName = launchedActivity.packageName; +            launchedActivityName = launchedActivity.info.name; +            launchedActivityLaunchedFromPackage = launchedActivity.launchedFromPackage; +            launchedActivityLaunchToken = launchedActivity.info.launchToken; +            launchedActivityAppRecordRequiredAbi = launchedActivity.app == null                      ? null                      : info.launchedActivity.app.getRequiredAbi();              reason = info.reason; @@ -204,6 +238,10 @@ class ActivityMetricsLogger {              type = getTransitionType(info);              processRecord = findProcessForActivity(info.launchedActivity);              processName = info.launchedActivity.processName; +            userId = launchedActivity.userId; +            launchedActivityShortComponentName = launchedActivity.shortComponentName; +            activityRecordIdHashCode = System.identityHashCode(launchedActivity); +            this.windowsFullyDrawnDelayMs = windowsFullyDrawnDelayMs;          }      } @@ -335,7 +373,7 @@ class ActivityMetricsLogger {                  || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {              // Failed to launch or it was not a process switch, so we don't care about the timing. -            reset(true /* abort */); +            reset(true /* abort */, info);              return;          } else if (otherWindowModesLaunching) {              // Don't log this windowing mode but continue with the other windowing modes. @@ -351,6 +389,7 @@ class ActivityMetricsLogger {          mWindowingModeTransitionInfo.put(windowingMode, newInfo);          mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);          mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000); +        startTraces(newInfo);      }      /** @@ -364,18 +403,21 @@ class ActivityMetricsLogger {      /**       * Notifies the tracker that all windows of the app have been drawn.       */ -    void notifyWindowsDrawn(int windowingMode, long timestamp) { +    WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(int windowingMode, long timestamp) {          if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);          final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);          if (info == null || info.loggedWindowsDrawn) { -            return; +            return null;          }          info.windowsDrawnDelayMs = calculateDelay(timestamp);          info.loggedWindowsDrawn = true; +        final WindowingModeTransitionInfoSnapshot infoSnapshot = +                new WindowingModeTransitionInfoSnapshot(info);          if (allWindowsDrawn() && mLoggedTransitionStarting) { -            reset(false /* abort */); +            reset(false /* abort */, info);          } +        return infoSnapshot;      }      /** @@ -394,7 +436,7 @@ class ActivityMetricsLogger {       * Notifies the tracker that the app transition is starting.       *       * @param windowingModeToReason A map from windowing mode to a reason integer, which must be on -     *                              of ActivityManagerInternal.APP_TRANSITION_* reasons. +     *                              of ActivityTaskManagerInternal.APP_TRANSITION_* reasons.       */      void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) {          if (!isAnyTransitionActive() || mLoggedTransitionStarting) { @@ -413,7 +455,7 @@ class ActivityMetricsLogger {              info.reason = windowingModeToReason.valueAt(index);          }          if (allWindowsDrawn()) { -            reset(false /* abort */); +            reset(false /* abort */, null /* WindowingModeTransitionInfo */);          }      } @@ -452,8 +494,9 @@ class ActivityMetricsLogger {                  logAppTransitionCancel(info);                  mWindowingModeTransitionInfo.remove(r.getWindowingMode());                  if (mWindowingModeTransitionInfo.size() == 0) { -                    reset(true /* abort */); +                    reset(true /* abort */, info);                  } +                stopFullyDrawnTraceIfNeeded();              }          }      } @@ -488,19 +531,19 @@ class ActivityMetricsLogger {                  && mWindowingModeTransitionInfo.size() > 0;      } -    private void reset(boolean abort) { +    private void reset(boolean abort, WindowingModeTransitionInfo info) {          if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);          if (!abort && isAnyTransitionActive()) {              logAppTransitionMultiEvents();          } +        stopLaunchTrace(info);          mCurrentTransitionStartTime = INVALID_START_TIME; -        mCurrentTransitionDelayMs = -1; +        mCurrentTransitionDelayMs = INVALID_DELAY;          mLoggedTransitionStarting = false;          mWindowingModeTransitionInfo.clear();      }      private int calculateCurrentDelay() { -          // Shouldn't take more than 25 days to launch an app, so int is fine here.          return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime);      } @@ -512,7 +555,7 @@ class ActivityMetricsLogger {      private void logAppTransitionCancel(WindowingModeTransitionInfo info) {          final int type = getTransitionType(info); -        if (type == -1) { +        if (type == INVALID_TRANSITION_TYPE) {              return;          }          final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED); @@ -533,7 +576,7 @@ class ActivityMetricsLogger {          for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {              final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(index);              final int type = getTransitionType(info); -            if (type == -1) { +            if (type == INVALID_TRANSITION_TYPE) {                  return;              } @@ -545,6 +588,7 @@ class ActivityMetricsLogger {              final int currentTransitionDelayMs = mCurrentTransitionDelayMs;              BackgroundThread.getHandler().post(() -> logAppTransition(                      currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot)); +            BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));              info.launchedActivity.info.launchToken = null;          } @@ -571,11 +615,11 @@ class ActivityMetricsLogger {                  currentTransitionDeviceUptime);          builder.addTaggedData(APP_TRANSITION_DELAY_MS, currentTransitionDelayMs);          builder.setSubtype(info.reason); -        if (info.startingWindowDelayMs != -1) { +        if (info.startingWindowDelayMs != INVALID_DELAY) {              builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,                      info.startingWindowDelayMs);          } -        if (info.bindApplicationDelayMs != -1) { +        if (info.bindApplicationDelayMs != INVALID_DELAY) {              builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,                      info.bindApplicationDelayMs);          } @@ -612,6 +656,24 @@ class ActivityMetricsLogger {          logAppStartMemoryStateCapture(info);      } +    private void logAppDisplayed(WindowingModeTransitionInfoSnapshot info) { +        if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) { +            return; +        } + +        EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME, +                info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName, +                info.windowsDrawnDelayMs); + +        StringBuilder sb = mStringBuilder; +        sb.setLength(0); +        sb.append("Displayed "); +        sb.append(info.launchedActivityShortComponentName); +        sb.append(": "); +        TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb); +        Log.i(TAG, sb.toString()); +    } +      private int convertAppStartTransitionType(int tronType) {          if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {              return StatsLog.APP_START_OCCURRED__TYPE__COLD; @@ -625,11 +687,12 @@ class ActivityMetricsLogger {          return StatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;       } -    void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) { +    WindowingModeTransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r, +            boolean restoredFromBundle) {          final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(                  r.getWindowingMode());          if (info == null) { -            return; +            return null;          }          final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);          builder.setPackageName(r.packageName); @@ -652,6 +715,25 @@ class ActivityMetricsLogger {                  info.launchedActivity.info.name,                  info.currentTransitionProcessRunning,                  startupTimeMs); +        stopFullyDrawnTraceIfNeeded(); +        final WindowingModeTransitionInfoSnapshot infoSnapshot = +                new WindowingModeTransitionInfoSnapshot(info, r, (int) startupTimeMs); +        BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot)); +        return infoSnapshot; +    } + +    private void logAppFullyDrawn(WindowingModeTransitionInfoSnapshot info) { +        if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) { +            return; +        } + +        StringBuilder sb = mStringBuilder; +        sb.setLength(0); +        sb.append("Fully drawn "); +        sb.append(info.launchedActivityShortComponentName); +        sb.append(": "); +        TimeUtils.formatDuration(info.windowsFullyDrawnDelayMs, sb); +        Log.i(TAG, sb.toString());      }      void logActivityStart(Intent intent, ProcessRecord callerApp, ActivityRecord r, @@ -753,7 +835,7 @@ class ActivityMetricsLogger {          } else if (info.startResult == START_SUCCESS) {              return TYPE_TRANSITION_COLD_LAUNCH;          } -        return -1; +        return INVALID_TRANSITION_TYPE;      }      private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) { @@ -798,4 +880,46 @@ class ActivityMetricsLogger {          }          return mArtManagerInternal;      } + +    /** +     * Starts traces for app launch and draw times. We stop the fully drawn trace if its already +     * active since the app may not have reported fully drawn in the previous launch. +     * +     * See {@link android.app.Activity#reportFullyDrawn()} +     * +     * @param info +     * */ +    private void startTraces(WindowingModeTransitionInfo info) { +        if (info == null) { +            return; +        } +        stopFullyDrawnTraceIfNeeded(); +        int transitionType = getTransitionType(info); +        if (!info.launchTraceActive && transitionType == TYPE_TRANSITION_WARM_LAUNCH +                || transitionType == TYPE_TRANSITION_COLD_LAUNCH) { +            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: " +                    + info.launchedActivity.packageName, 0); +            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); +            mDrawingTraceActive = true; +            info.launchTraceActive = true; +        } +    } + +    private void stopLaunchTrace(WindowingModeTransitionInfo info) { +        if (info == null) { +            return; +        } +        if (info.launchTraceActive) { +            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: " +                    + info.launchedActivity.packageName, 0); +            info.launchTraceActive = false; +        } +    } + +    void stopFullyDrawnTraceIfNeeded() { +        if (mDrawingTraceActive) { +            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); +            mDrawingTraceActive = false; +        } +    }  } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 77cfb124ec80..5853ad976bbb 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -31,6 +31,7 @@ import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;  import static android.app.ActivityTaskManager.INVALID_STACK_ID;  import static android.app.AppOpsManager.MODE_ALLOWED;  import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE; +import static android.app.WaitResult.INVALID_DELAY;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -80,7 +81,6 @@ import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;  import static android.os.Build.VERSION_CODES.HONEYCOMB;  import static android.os.Build.VERSION_CODES.O;  import static android.os.Process.SYSTEM_UID; -import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;  import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;  import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; @@ -112,8 +112,6 @@ import static com.android.server.am.ActivityStack.LAUNCH_TICK;  import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG;  import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG;  import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG; -import static com.android.server.am.EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME; -import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;  import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;  import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;  import static com.android.server.am.TaskPersister.DEBUG; @@ -164,7 +162,6 @@ import android.os.PersistableBundle;  import android.os.Process;  import android.os.RemoteException;  import android.os.SystemClock; -import android.os.Trace;  import android.os.UserHandle;  import android.os.storage.StorageManager;  import android.service.voice.IVoiceInteractionSession; @@ -186,6 +183,7 @@ import com.android.internal.content.ReferrerIntent;  import com.android.internal.util.XmlUtils;  import com.android.server.AttributeCache;  import com.android.server.AttributeCache.Entry; +import com.android.server.am.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;  import com.android.server.am.ActivityStack.ActivityState;  import com.android.server.uri.UriPermissionOwner;  import com.android.server.wm.AppWindowContainerController; @@ -266,9 +264,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo      private int windowFlags;        // custom window flags for preview window.      private TaskRecord task;        // the task this is in.      private long createTime = System.currentTimeMillis(); -    long displayStartTime;  // when we started launching this activity -    long fullyDrawnStartTime; // when we started launching this activity -    private long startTime;         // last time this activity was started      long lastVisibleTime;   // last time this activity became visible      long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity      long pauseTime;         // last time we started pausing the activity @@ -536,15 +531,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo              pw.print("requestedVrComponent=");              pw.println(requestedVrComponent);          } -        if (displayStartTime != 0 || startTime != 0) { -            pw.print(prefix); pw.print("displayStartTime="); -                    if (displayStartTime == 0) pw.print("0"); -                    else TimeUtils.formatDuration(displayStartTime, now, pw); -                    pw.print(" startTime="); -                    if (startTime == 0) pw.print("0"); -                    else TimeUtils.formatDuration(startTime, now, pw); -                    pw.println(); -        }          final boolean waitingVisible =                  mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this);          if (lastVisibleTime != 0 || waitingVisible || nowVisible) { @@ -2006,79 +1992,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo      }      public void reportFullyDrawnLocked(boolean restoredFromBundle) { -        final long curTime = SystemClock.uptimeMillis(); -        if (displayStartTime != 0) { -            reportLaunchTimeLocked(curTime); -        } -        final LaunchTimeTracker.Entry entry = mStackSupervisor.getLaunchTimeTracker().getEntry( -                getWindowingMode()); -        if (fullyDrawnStartTime != 0 && entry != null) { -            final long thisTime = curTime - fullyDrawnStartTime; -            final long totalTime = entry.mFullyDrawnStartTime != 0 -                    ? (curTime - entry.mFullyDrawnStartTime) : thisTime; -            if (SHOW_ACTIVITY_START_TIME) { -                Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); -                EventLog.writeEvent(AM_ACTIVITY_FULLY_DRAWN_TIME, -                        userId, System.identityHashCode(this), shortComponentName, -                        thisTime, totalTime); -                StringBuilder sb = service.mStringBuilder; -                sb.setLength(0); -                sb.append("Fully drawn "); -                sb.append(shortComponentName); -                sb.append(": "); -                TimeUtils.formatDuration(thisTime, sb); -                if (thisTime != totalTime) { -                    sb.append(" (total "); -                    TimeUtils.formatDuration(totalTime, sb); -                    sb.append(")"); -                } -                Log.i(TAG, sb.toString()); -            } -            if (totalTime > 0) { -                //service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime); -            } -            entry.mFullyDrawnStartTime = 0; -        } -        mStackSupervisor.getActivityMetricsLogger().logAppTransitionReportedDrawn(this, -                restoredFromBundle); -        fullyDrawnStartTime = 0; -    } - -    private void reportLaunchTimeLocked(final long curTime) { -        final LaunchTimeTracker.Entry entry = mStackSupervisor.getLaunchTimeTracker().getEntry( -                getWindowingMode()); -        if (entry == null) { -            return; -        } -        final long thisTime = curTime - displayStartTime; -        final long totalTime = entry.mLaunchStartTime != 0 -                ? (curTime - entry.mLaunchStartTime) : thisTime; -        if (SHOW_ACTIVITY_START_TIME) { -            Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0); -            EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME, -                    userId, System.identityHashCode(this), shortComponentName, -                    thisTime, totalTime); -            StringBuilder sb = service.mStringBuilder; -            sb.setLength(0); -            sb.append("Displayed "); -            sb.append(shortComponentName); -            sb.append(": "); -            TimeUtils.formatDuration(thisTime, sb); -            if (thisTime != totalTime) { -                sb.append(" (total "); -                TimeUtils.formatDuration(totalTime, sb); -                sb.append(")"); -            } -            Log.i(TAG, sb.toString()); -        } -        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime); -        if (totalTime > 0) { -            //service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime); +        final WindowingModeTransitionInfoSnapshot info = mStackSupervisor +                .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); +        if (info != null) { +            mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, +                    info.windowsFullyDrawnDelayMs);          } -        displayStartTime = 0; -        entry.mLaunchStartTime = 0;      } -      @Override      public void onStartingWindowDrawn(long timestamp) {          synchronized (service.mGlobalLock) { @@ -2090,13 +2010,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo      @Override      public void onWindowsDrawn(long timestamp) {          synchronized (service.mGlobalLock) { -            mStackSupervisor.getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), -                    timestamp); -            if (displayStartTime != 0) { -                reportLaunchTimeLocked(timestamp); -            } +            final WindowingModeTransitionInfoSnapshot info = mStackSupervisor +                    .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestamp); +            final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY; +            mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, +                    windowsDrawnDelayMs);              mStackSupervisor.sendWaitingVisibleReportLocked(this); -            startTime = 0;              finishLaunchTickingLocked();              if (task != null) {                  task.hasBeenVisible = true; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 35a1eb8ff616..29b04ccdab08 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -151,7 +151,6 @@ import android.view.Display;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.app.IVoiceInteractor; -import com.android.internal.os.BatteryStatsImpl;  import com.android.internal.util.function.pooled.PooledLambda;  import com.android.server.Watchdog;  import com.android.server.am.ActivityManagerService.ItemMatcher; @@ -1319,16 +1318,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai                  + " callers=" + Debug.getCallers(5));          r.setState(RESUMED, "minimalResumeActivityLocked");          r.completeResumeLocked(); -        mStackSupervisor.getLaunchTimeTracker().setLaunchTime(r);          if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,                  "Launch completed; removing icicle of " + r.icicle);      }      private void clearLaunchTime(ActivityRecord r) {          // Make sure that there is no activity waiting for this to launch. -        if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) { -            r.displayStartTime = r.fullyDrawnStartTime = 0; -        } else { +        if (!mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {              mStackSupervisor.removeTimeoutsForActivityLocked(r);              mStackSupervisor.scheduleIdleTimeoutLocked(r);          } @@ -1514,7 +1510,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai          prev.getTask().touchActiveTime();          clearLaunchTime(prev); -        mStackSupervisor.getLaunchTimeTracker().stopFullyDrawnTraceIfNeeded(getWindowingMode()); +        mStackSupervisor.getActivityMetricsLogger().stopFullyDrawnTraceIfNeeded();          mService.updateCpuStats(); @@ -2450,13 +2446,24 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai          if (shouldSleepOrShutDownActivities()                  && mLastPausedActivity == next                  && mStackSupervisor.allPausedActivitiesComplete()) { -            // Make sure we have executed any pending transitions, since there -            // should be nothing left to do at this point. -            executeAppTransition(options); -            if (DEBUG_STATES) Slog.d(TAG_STATES, -                    "resumeTopActivityLocked: Going to sleep and all paused"); -            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); -            return false; +            // If the current top activity may be able to occlude keyguard but the occluded state +            // has not been set, update visibility and check again if we should continue to resume. +            boolean nothingToResume = true; +            if (!mService.mShuttingDown && !mTopActivityOccludesKeyguard +                    && next.canShowWhenLocked()) { +                ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, +                        !PRESERVE_WINDOWS); +                nothingToResume = shouldSleepActivities(); +            } +            if (nothingToResume) { +                // Make sure we have executed any pending transitions, since there +                // should be nothing left to do at this point. +                executeAppTransition(options); +                if (DEBUG_STATES) Slog.d(TAG_STATES, +                        "resumeTopActivityLocked: Going to sleep and all paused"); +                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); +                return false; +            }          }          // Make sure that the user who owns this activity is started.  If not, @@ -4144,7 +4151,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai              for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {                  PendingIntentRecord rec = apr.get();                  if (rec != null) { -                    mService.mAm.cancelIntentSenderLocked(rec, false); +                    mService.mPendingIntentController.cancelIntentSender(rec, false);                  }              }              r.pendingResults = null; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 877c8567b9d0..9688d263643c 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -25,6 +25,7 @@ import static android.app.ActivityManager.START_TASK_TO_FRONT;  import static android.app.ActivityTaskManager.INVALID_STACK_ID;  import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;  import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; +import static android.app.WaitResult.INVALID_DELAY;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -450,7 +451,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D      private boolean mTaskLayersChanged = true;      private ActivityMetricsLogger mActivityMetricsLogger; -    private LaunchTimeTracker mLaunchTimeTracker = new LaunchTimeTracker();      private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>(); @@ -646,10 +646,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D          return mActivityMetricsLogger;      } -    LaunchTimeTracker getLaunchTimeTracker() { -        return mLaunchTimeTracker; -    } -      public KeyguardController getKeyguardController() {          return mKeyguardController;      } @@ -1179,8 +1175,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D          }      } -    void waitActivityVisible(ComponentName name, WaitResult result) { -        final WaitInfo waitInfo = new WaitInfo(name, result); +    void waitActivityVisible(ComponentName name, WaitResult result, long startTimeMs) { +        final WaitInfo waitInfo = new WaitInfo(name, result, startTimeMs);          mWaitingForActivityVisible.add(waitInfo);      } @@ -1211,8 +1207,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D                  changed = true;                  result.timeout = false;                  result.who = w.getComponent(); -                result.totalTime = SystemClock.uptimeMillis() - result.thisTime; -                result.thisTime = result.totalTime; +                result.totalTime = SystemClock.uptimeMillis() - w.getStartTime();                  mWaitingForActivityVisible.remove(w);              }          } @@ -1251,8 +1246,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D          }      } -    void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, -            long thisTime, long totalTime) { +    void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime) {          boolean changed = false;          for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {              WaitResult w = mWaitingActivityLaunched.remove(i); @@ -1262,7 +1256,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D                  if (r != null) {                      w.who = new ComponentName(r.info.packageName, r.info.name);                  } -                w.thisTime = thisTime;                  w.totalTime = totalTime;                  // Do not modify w.result.              } @@ -1728,8 +1721,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D          ProcessRecord app = mService.mAm.getProcessRecordLocked(r.processName,                  r.info.applicationInfo.uid, true); -        getLaunchTimeTracker().setLaunchTime(r); -          if (app != null && app.thread != null) {              try {                  if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 @@ -2082,7 +2073,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D              mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);              r.finishLaunchTickingLocked();              if (fromTimeout) { -                reportActivityLaunchedLocked(fromTimeout, r, -1, -1); +                reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY);              }              // This is a hack to semi-deal with a race condition @@ -4940,10 +4931,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D      static class WaitInfo {          private final ComponentName mTargetComponent;          private final WaitResult mResult; +        /** Time stamp when we started to wait for {@link WaitResult}. */ +        private final long mStartTimeMs; -        public WaitInfo(ComponentName targetComponent, WaitResult result) { +        WaitInfo(ComponentName targetComponent, WaitResult result, long startTimeMs) {              this.mTargetComponent = targetComponent;              this.mResult = result; +            this.mStartTimeMs = startTimeMs;          }          public boolean matches(ComponentName targetComponent) { @@ -4954,6 +4948,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D              return mResult;          } +        public long getStartTime() { +            return mStartTimeMs; +        } +          public ComponentName getComponent() {              return mTargetComponent;          } diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 177e2f563a4b..1fb8f871efcd 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -126,7 +126,7 @@ class ActivityStartInterceptor {      private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {          Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary(); -        final IIntentSender target = mService.mAm.getIntentSenderLocked( +        final IIntentSender target = mService.getIntentSenderLocked(                  INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,                  null /*resultCode*/, 0 /*requestCode*/,                  new Intent[] { mIntent }, new String[] { mResolvedType }, diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 7da0519ef2f0..8236bd0e763e 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -783,7 +783,7 @@ class ActivityStarter {          if (aInfo != null) {              if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(                      aInfo.packageName, userId)) { -                IIntentSender target = mService.mAm.getIntentSenderLocked( +                IIntentSender target = mService.getIntentSenderLocked(                          ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,                          callingUid, userId, null, null, 0, new Intent[]{intent},                          new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT @@ -1096,7 +1096,7 @@ class ActivityStarter {                              }                          } -                        IIntentSender target = mService.mAm.getIntentSenderLocked( +                        IIntentSender target = mService.getIntentSenderLocked(                                  ActivityManager.INTENT_SENDER_ACTIVITY, "android",                                  appCallingUid, userId, null, null, 0, new Intent[] { intent },                                  new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT @@ -1154,6 +1154,9 @@ class ActivityStarter {                  mService.updateConfigurationLocked(globalConfig, null, false);              } +            // Notify ActivityMetricsLogger that the activity has launched. ActivityMetricsLogger +            // will then wait for the windows to be drawn and populate WaitResult. +            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);              if (outResult != null) {                  outResult.result = res; @@ -1178,7 +1181,6 @@ class ActivityStarter {                          outResult.timeout = false;                          outResult.who = r.realActivity;                          outResult.totalTime = 0; -                        outResult.thisTime = 0;                          break;                      }                      case START_TASK_TO_FRONT: { @@ -1188,10 +1190,9 @@ class ActivityStarter {                              outResult.timeout = false;                              outResult.who = r.realActivity;                              outResult.totalTime = 0; -                            outResult.thisTime = 0;                          } else { -                            outResult.thisTime = SystemClock.uptimeMillis(); -                            mSupervisor.waitActivityVisible(r.realActivity, outResult); +                            final long startTimeMs = SystemClock.uptimeMillis(); +                            mSupervisor.waitActivityVisible(r.realActivity, outResult, startTimeMs);                              // Note: the timeout variable is not currently not ever set.                              do {                                  try { @@ -1205,7 +1206,6 @@ class ActivityStarter {                  }              } -            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);              return res;          }      } diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 4dc28510c5ec..36261b505a94 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -239,7 +239,9 @@ import java.io.FileOutputStream;  import java.io.IOException;  import java.io.PrintWriter;  import java.io.StringWriter; +import java.lang.ref.WeakReference;  import java.util.ArrayList; +import java.util.HashSet;  import java.util.List;  import java.util.Locale; @@ -276,6 +278,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {      UriGrantsManagerInternal mUgmInternal;      private PackageManagerInternal mPmInternal;      private ActivityTaskManagerInternal mInternal; +    PendingIntentController mPendingIntentController;      /* Global service lock used by the package the owns this service. */      Object mGlobalLock;      ActivityStackSupervisor mStackSupervisor; @@ -628,6 +631,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {          final File systemDir = SystemServiceManager.ensureSystemDir();          mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir);          mCompatModePackages = new CompatModePackages(this, systemDir, mH); +        mPendingIntentController = mAm.mPendingIntentController;          mTempConfig.setToDefaults();          mTempConfig.setLocales(LocaleList.getDefault()); @@ -1956,10 +1960,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {              final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);              if (task == null) {                  Slog.d(TAG, "Could not find task for id: "+ taskId); +                SafeActivityOptions.abort(options);                  return;              }              if (getLockTaskController().isLockTaskModeViolation(task)) {                  Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode"); +                SafeActivityOptions.abort(options);                  return;              }              ActivityOptions realOptions = options != null @@ -1979,7 +1985,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {          } finally {              Binder.restoreCallingIdentity(origId);          } -        SafeActivityOptions.abort(options);      }      boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid, @@ -5019,6 +5024,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {      } +    IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId, +            IBinder token, String resultWho, int requestCode, Intent[] intents, +            String[] resolvedTypes, int flags, Bundle bOptions) { + +        ActivityRecord activity = null; +        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { +            activity = ActivityRecord.isInStackLocked(token); +            if (activity == null) { +                Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); +                return null; +            } +            if (activity.finishing) { +                Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); +                return null; +            } +        } + +        final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName, +                callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags, +                bOptions); +        final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; +        if (noCreate) { +            return rec; +        } +        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { +            if (activity.pendingResults == null) { +                activity.pendingResults = new HashSet<>(); +            } +            activity.pendingResults.add(rec.ref); +        } +        return rec; +    } +      // TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities      private void startTimeTrackingFocusedActivityLocked() {          final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity(); @@ -5310,6 +5348,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {          }          @Override +        public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, +                String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, +                boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { +            synchronized (mGlobalLock) { +                return getActivityStartController().startActivitiesInPackage(uid, callingPackage, +                        intents, resolvedTypes, resultTo, options, userId, validateIncomingUser, +                        originatingPendingIntent); +            } +        } + +        @Override +        public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, +                String callingPackage, Intent intent, String resolvedType, IBinder resultTo, +                String resultWho, int requestCode, int startFlags, SafeActivityOptions options, +                int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, +                PendingIntentRecord originatingPendingIntent) { +            synchronized (mGlobalLock) { +                return getActivityStartController().startActivityInPackage(uid, realCallingPid, +                        realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho, +                        requestCode, startFlags, options, userId, inTask, reason, +                        validateIncomingUser, originatingPendingIntent); +            } +        } + +        @Override          public int startActivityAsUser(IApplicationThread caller, String callerPacakge,                  Intent intent, Bundle options, int userId) {              return ActivityTaskManagerService.this.startActivityAsUser( @@ -5684,5 +5747,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {                  }              });          } + +        @Override +        public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho, +                int requestCode, int resultCode, Intent data) { +            synchronized (mGlobalLock) { +                final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); +                if (r != null && r.getStack() != null) { +                    r.getStack().sendActivityResultLocked(callingUid, r, resultWho, requestCode, +                            resultCode, data); +                } +            } +        } + +        @Override +        public void clearPendingResultForActivity(IBinder activityToken, +                WeakReference<PendingIntentRecord> pir) { +            synchronized (mGlobalLock) { +                final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); +                if (r != null && r.pendingResults != null) { +                    r.pendingResults.remove(pir); +                } +            } +        } + +        @Override +        public IIntentSender getIntentSender(int type, String packageName, +                int callingUid, int userId, IBinder token, String resultWho, +                int requestCode, Intent[] intents, String[] resolvedTypes, int flags, +                Bundle bOptions) { +            synchronized (mGlobalLock) { +                return getIntentSenderLocked(type, packageName, callingUid, userId, token, +                        resultWho, requestCode, intents, resolvedTypes, flags, bOptions); +            } +        }      }  } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 16c3235cd729..e2035f67031a 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -741,7 +741,7 @@ public final class BroadcastQueue {          // Show a permission review UI only for explicit broadcast from a foreground app          if (callerForeground && receiverRecord.intent.getComponent() != null) { -            IIntentSender target = mService.getIntentSenderLocked( +            IIntentSender target = mService.mPendingIntentController.getIntentSender(                      ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage,                      receiverRecord.callingUid, receiverRecord.userId, null, null, 0,                      new Intent[]{receiverRecord.intent}, diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index ed891dfb0e70..0ef2a0a90e13 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -87,9 +87,6 @@ option java_package com.android.server.am  # User switched  30041 am_switch_user (id|1|5) -# Activity fully drawn time -30042 am_activity_fully_drawn_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3) -  # Activity set to resumed  30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3) diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index ee4e36ff1fd1..cfe282917f3b 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -29,16 +29,20 @@ import static android.view.WindowManager.TRANSIT_UNSET;  import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;  import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;  import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; +  import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;  import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED; +import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;  import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING; +import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID; +import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;  import android.os.IBinder;  import android.os.RemoteException;  import android.os.Trace;  import android.util.Slog; +import android.util.SparseArray;  import android.util.proto.ProtoOutputStream;  import com.android.internal.policy.IKeyguardDismissCallback; @@ -58,19 +62,18 @@ class KeyguardController {      private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM; -    private final ActivityTaskManagerService mService;      private final ActivityStackSupervisor mStackSupervisor;      private WindowManagerService mWindowManager;      private boolean mKeyguardShowing;      private boolean mAodShowing;      private boolean mKeyguardGoingAway; -    private boolean mOccluded;      private boolean mDismissalRequested; -    private ActivityRecord mDismissingKeyguardActivity;      private int mBeforeUnoccludeTransit;      private int mVisibilityTransactionDepth; -    private SleepToken mSleepToken; +    // TODO(b/111955725): Support multiple external displays      private int mSecondaryDisplayShowing = INVALID_DISPLAY; +    private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); +    private final ActivityTaskManagerService mService;      KeyguardController(ActivityTaskManagerService service,              ActivityStackSupervisor stackSupervisor) { @@ -87,8 +90,8 @@ class KeyguardController {       *         on the given display, false otherwise       */      boolean isKeyguardOrAodShowing(int displayId) { -        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway && -                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); +        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway +                && !isDisplayOccluded(displayId);      }      /** @@ -96,8 +99,7 @@ class KeyguardController {       *         display, false otherwise       */      boolean isKeyguardShowing(int displayId) { -        return mKeyguardShowing && !mKeyguardGoingAway && -                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); +        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);      }      /** @@ -133,6 +135,7 @@ class KeyguardController {          if (showingChanged) {              dismissDockedStackIfNeeded();              setKeyguardGoingAway(false); +            // TODO(b/113840485): Check usage for non-default display              mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(                      isKeyguardOrAodShowing(DEFAULT_DISPLAY));              if (keyguardShowing) { @@ -248,7 +251,8 @@ class KeyguardController {          // already the dismissing activity, in which case we don't allow it to repeatedly dismiss          // Keyguard.          return dismissKeyguard && canDismissKeyguard() && !mAodShowing -                && (mDismissalRequested || r != mDismissingKeyguardActivity); +                && (mDismissalRequested +                || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r);      }      /** @@ -259,44 +263,16 @@ class KeyguardController {      }      private void visibilitiesUpdated() { -        final boolean lastOccluded = mOccluded; -        final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; -        mOccluded = false; -        mDismissingKeyguardActivity = null; - +        boolean requestDismissKeyguard = false;          for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {              final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); -            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { -                final ActivityStack stack = display.getChildAt(stackNdx); - -                // Only the top activity of the focused stack on the default display may control -                // occluded state. -                if (display.mDisplayId == DEFAULT_DISPLAY -                        && mStackSupervisor.isTopDisplayFocusedStack(stack)) { - -                    // A dismissing activity occludes Keyguard in the insecure case for legacy -                    // reasons. -                    final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity(); -                    mOccluded = -                            stack.topActivityOccludesKeyguard() -                                    || (topDismissing != null -                                            && stack.topRunningActivityLocked() == topDismissing -                                            && canShowWhileOccluded( -                                                    true /* dismissKeyguard */, -                                                    false /* showWhenLocked */)); -                } - -                if (mDismissingKeyguardActivity == null -                        && stack.getTopDismissingKeyguardActivity() != null) { -                    mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity(); -                } -            } -        } -        mOccluded |= mWindowManager.isShowingDream(); -        if (mOccluded != lastOccluded) { -            handleOccludedChanged(); +            final KeyguardDisplayState state = getDisplay(display.mDisplayId); +            state.visibilitiesUpdated(this, display); +            requestDismissKeyguard |= state.mRequestDismissKeyguard;          } -        if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) { + +        // Dismissing Keyguard happens globally using the information from all displays. +        if (requestDismissKeyguard) {              handleDismissKeyguard();          }      } @@ -305,7 +281,7 @@ class KeyguardController {       * Called when occluded state changed.       */      private void handleOccludedChanged() { -        mWindowManager.onKeyguardOccludedChanged(mOccluded); +        mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));          if (isKeyguardLocked()) {              mWindowManager.deferSurfaceLayout();              try { @@ -322,14 +298,13 @@ class KeyguardController {      }      /** -     * Called when somebody might want to dismiss the Keyguard. +     * Called when somebody wants to dismiss the Keyguard via the flag.       */      private void handleDismissKeyguard() {          // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy          // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the          // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded. -        if (!mOccluded && mDismissingKeyguardActivity != null -                && mWindowManager.isKeyguardSecure()) { +        if (mWindowManager.isKeyguardSecure()) {              mWindowManager.dismissKeyguard(null /* callback */, null /* message */);              mDismissalRequested = true; @@ -345,6 +320,10 @@ class KeyguardController {          }      } +    private boolean isDisplayOccluded(int displayId) { +        return getDisplay(displayId).mOccluded; +    } +      /**       * @return true if Keyguard can be currently dismissed without entering credentials.       */ @@ -355,12 +334,14 @@ class KeyguardController {      private int resolveOccludeTransit() {          if (mBeforeUnoccludeTransit != TRANSIT_UNSET                  && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE -                && mOccluded) { +                // TODO(b/113840485): Handle app transition for individual display. +                && isDisplayOccluded(DEFAULT_DISPLAY)) {              // Reuse old transit in case we are occluding Keyguard again, meaning that we never              // actually occclude/unocclude Keyguard, but just run a normal transition.              return mBeforeUnoccludeTransit; -        } else if (!mOccluded) { +            // TODO(b/113840485): Handle app transition for individual display. +        } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {              // Save transit in case we dismiss/occlude Keyguard shortly after.              mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition(); @@ -371,7 +352,8 @@ class KeyguardController {      }      private void dismissDockedStackIfNeeded() { -        if (mKeyguardShowing && mOccluded) { +        // TODO(b/113840485): Handle docked stack for individual display. +        if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {              // The lock screen is currently showing, but is occluded by a window that can              // show on top of the lock screen. In this can we want to dismiss the docked              // stack since it will be complicated/risky to try to put the activity on top @@ -386,11 +368,116 @@ class KeyguardController {      }      private void updateKeyguardSleepToken() { -        if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { -            mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY); -        } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { -            mSleepToken.release(); -            mSleepToken = null; +        for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { +            final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); +            final KeyguardDisplayState state = getDisplay(display.mDisplayId); +            if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) { +                state.acquiredSleepToken(); +            } else if (!isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken != null) { +                state.releaseSleepToken(); +            } +        } +    } + +    private KeyguardDisplayState getDisplay(int displayId) { +        if (mDisplayStates.get(displayId) == null) { +            mDisplayStates.append(displayId, +                    new KeyguardDisplayState(mService, displayId)); +        } +        return mDisplayStates.get(displayId); +    } + +    void onDisplayRemoved(int displayId) { +        if (mDisplayStates.get(displayId) != null) { +            mDisplayStates.get(displayId).onRemoved(); +            mDisplayStates.remove(displayId); +        } +    } + +    /** Represents Keyguard state per individual display. */ +    private static class KeyguardDisplayState { +        private final int mDisplayId; +        private boolean mOccluded; +        private ActivityRecord mDismissingKeyguardActivity; +        private boolean mRequestDismissKeyguard; +        private final ActivityTaskManagerService mService; +        private SleepToken mSleepToken; + +        KeyguardDisplayState(ActivityTaskManagerService service, int displayId) { +            mService = service; +            mDisplayId = displayId; +        } + +        void onRemoved() { +            mDismissingKeyguardActivity = null; +            releaseSleepToken(); +        } + +        void acquiredSleepToken() { +            if (mSleepToken == null) { +                mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId); +            } +        } + +        void releaseSleepToken() { +            if (mSleepToken != null) { +                mSleepToken.release(); +                mSleepToken = null; +            } +        } + +        void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) { +            final boolean lastOccluded = mOccluded; +            final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity; +            mRequestDismissKeyguard = false; +            mOccluded = false; +            mDismissingKeyguardActivity = null; + +            // Only the top activity of the focused stack on each display may control it's +            // occluded state. +            final ActivityStack focusedStack = display.getFocusedStack(); +            if (focusedStack != null) { +                final ActivityRecord topDismissing = +                        focusedStack.getTopDismissingKeyguardActivity(); +                mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null +                                && focusedStack.topRunningActivityLocked() == topDismissing +                                && controller.canShowWhileOccluded( +                                true /* dismissKeyguard */, +                                false /* showWhenLocked */)); +                if (focusedStack.getTopDismissingKeyguardActivity() != null) { +                    mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity(); +                } +                mOccluded |= controller.mWindowManager.isShowingDream(); +            } + +            // TODO(b/113840485): Handle app transition for individual display. +            // For now, only default display can change occluded. +            if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) { +                controller.handleOccludedChanged(); +            } +            if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded +                    && mDismissingKeyguardActivity != null +                    && controller.mWindowManager.isKeyguardSecure()) { +                mRequestDismissKeyguard = true; +            } +        } + +        void dumpStatus(PrintWriter pw, String prefix) { +            final StringBuilder sb = new StringBuilder(); +            sb.append(prefix); +            sb.append("  Occluded=").append(mOccluded) +                    .append(" DismissingKeyguardActivity=") +                    .append(mDismissingKeyguardActivity) +                    .append(" at display=") +                    .append(mDisplayId); +            pw.println(sb.toString()); +        } + +        void writeToProto(ProtoOutputStream proto, long fieldId) { +            final long token = proto.start(fieldId); +            proto.write(DISPLAY_ID, mDisplayId); +            proto.write(KEYGUARD_OCCLUDED, mOccluded); +            proto.end(token);          }      } @@ -399,8 +486,7 @@ class KeyguardController {          pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);          pw.println(prefix + "  mAodShowing=" + mAodShowing);          pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway); -        pw.println(prefix + "  mOccluded=" + mOccluded); -        pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity); +        dumpDisplayStates(pw, prefix);          pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);          pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);      } @@ -408,7 +494,19 @@ class KeyguardController {      void writeToProto(ProtoOutputStream proto, long fieldId) {          final long token = proto.start(fieldId);          proto.write(KEYGUARD_SHOWING, mKeyguardShowing); -        proto.write(KEYGUARD_OCCLUDED, mOccluded); +        writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES);          proto.end(token);      } + +    private void dumpDisplayStates(PrintWriter pw, String prefix) { +        for (int i = 0; i < mDisplayStates.size(); i++) { +            mDisplayStates.valueAt(i).dumpStatus(pw, prefix); +        } +    } + +    private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) { +        for (int i = 0; i < mDisplayStates.size(); i++) { +            mDisplayStates.valueAt(i).writeToProto(proto, fieldId); +        } +    }  } diff --git a/services/core/java/com/android/server/am/LaunchTimeTracker.java b/services/core/java/com/android/server/am/LaunchTimeTracker.java deleted file mode 100644 index ee869691f7ca..000000000000 --- a/services/core/java/com/android/server/am/LaunchTimeTracker.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.am; - -import android.app.WaitResult; -import android.os.SystemClock; -import android.os.Trace; -import android.util.SparseArray; - -/** - * Tracks launch time of apps to be reported by {@link WaitResult}. Note that this is slightly - * different from {@link ActivityMetricsLogger}, but should eventually merged with it. - */ -class LaunchTimeTracker { - -    private final SparseArray<Entry> mWindowingModeLaunchTime = new SparseArray<>(); - -    void setLaunchTime(ActivityRecord r) { -        Entry entry = mWindowingModeLaunchTime.get(r.getWindowingMode()); -        if (entry == null){ -            entry = new Entry(); -            mWindowingModeLaunchTime.append(r.getWindowingMode(), entry); -        } -        entry.setLaunchTime(r); -    } - -    void stopFullyDrawnTraceIfNeeded(int windowingMode) { -        final Entry entry = mWindowingModeLaunchTime.get(windowingMode); -        if (entry == null) { -            return; -        } -        entry.stopFullyDrawnTraceIfNeeded(); -    } - -    Entry getEntry(int windowingMode) { -        return mWindowingModeLaunchTime.get(windowingMode); -    } - -    static class Entry { - -        long mLaunchStartTime; -        long mFullyDrawnStartTime; - -        void setLaunchTime(ActivityRecord r) { -            if (r.displayStartTime == 0) { -                r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis(); -                if (mLaunchStartTime == 0) { -                    startLaunchTraces(r.packageName); -                    mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime; -                } -            } else if (mLaunchStartTime == 0) { -                startLaunchTraces(r.packageName); -                mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis(); -            } -        } - -        private void startLaunchTraces(String packageName) { -            if (mFullyDrawnStartTime != 0)  { -                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); -            } -            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0); -            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); -        } - -        private void stopFullyDrawnTraceIfNeeded() { -            if (mFullyDrawnStartTime != 0 && mLaunchStartTime == 0) { -                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); -                mFullyDrawnStartTime = 0; -            } -        } -    } -} diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index aad890b8bd74..a8e1ccca8b9d 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -37,18 +37,26 @@ import java.util.regex.Pattern;   * Static utility methods related to {@link MemoryStat}.   */  final class MemoryStatUtil { +    static final int BYTES_IN_KILOBYTE = 1024; +    static final int PAGE_SIZE = 4096; +      private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;      /** True if device has per-app memcg */ -    private static final Boolean DEVICE_HAS_PER_APP_MEMCG = +    private static final boolean DEVICE_HAS_PER_APP_MEMCG =              SystemProperties.getBoolean("ro.config.per_app_memcg", false);      /** Path to check if device has memcg */      private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat";      /** Path to memory stat file for logging app start memory state */      private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat"; +    /** Path to memory max usage file for logging app memory state */ +    private static final String MEMORY_MAX_USAGE_FILE_FMT = +            "/dev/memcg/apps/uid_%d/pid_%d/memory.max_usage_in_bytes";      /** Path to procfs stat file for logging app start memory state */      private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat"; +    /** Path to procfs status file for logging app memory state */ +    private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";      private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");      private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)"); @@ -56,9 +64,12 @@ final class MemoryStatUtil {      private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");      private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)"); +    private static final Pattern RSS_HIGH_WATERMARK_IN_BYTES = +            Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); +      private static final int PGFAULT_INDEX = 9;      private static final int PGMAJFAULT_INDEX = 11; -    private static final int RSS_IN_BYTES_INDEX = 23; +    private static final int RSS_IN_PAGES_INDEX = 23;      private MemoryStatUtil() {} @@ -80,8 +91,15 @@ final class MemoryStatUtil {       */      @Nullable      static MemoryStat readMemoryStatFromMemcg(int uid, int pid) { -        final String path = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid); -        return parseMemoryStatFromMemcg(readFileContents(path)); +        final String statPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid); +        MemoryStat stat = parseMemoryStatFromMemcg(readFileContents(statPath)); +        if (stat == null) { +            return null; +        } +        String maxUsagePath = String.format(Locale.US, MEMORY_MAX_USAGE_FILE_FMT, uid, pid); +        stat.rssHighWatermarkInBytes = parseMemoryMaxUsageFromMemCg( +                readFileContents(maxUsagePath)); +        return stat;      }      /** @@ -91,8 +109,14 @@ final class MemoryStatUtil {       */      @Nullable      static MemoryStat readMemoryStatFromProcfs(int pid) { -        final String path = String.format(Locale.US, PROC_STAT_FILE_FMT, pid); -        return parseMemoryStatFromProcfs(readFileContents(path)); +        final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid); +        MemoryStat stat = parseMemoryStatFromProcfs(readFileContents(statPath)); +        if (stat == null) { +            return null; +        } +        final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid); +        stat.rssHighWatermarkInBytes = parseVmHWMFromProcfs(readFileContents(statusPath)); +        return stat;      }      private static String readFileContents(String path) { @@ -113,7 +137,7 @@ final class MemoryStatUtil {      /**       * Parses relevant statistics out from the contents of a memory.stat file in memcg.       */ -    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) +    @VisibleForTesting      @Nullable      static MemoryStat parseMemoryStatFromMemcg(String memoryStatContents) {          if (memoryStatContents == null || memoryStatContents.isEmpty()) { @@ -123,22 +147,35 @@ final class MemoryStatUtil {          final MemoryStat memoryStat = new MemoryStat();          Matcher m;          m = PGFAULT.matcher(memoryStatContents); -        memoryStat.pgfault = m.find() ? Long.valueOf(m.group(1)) : 0; +        memoryStat.pgfault = m.find() ? Long.parseLong(m.group(1)) : 0;          m = PGMAJFAULT.matcher(memoryStatContents); -        memoryStat.pgmajfault = m.find() ? Long.valueOf(m.group(1)) : 0; +        memoryStat.pgmajfault = m.find() ? Long.parseLong(m.group(1)) : 0;          m = RSS_IN_BYTES.matcher(memoryStatContents); -        memoryStat.rssInBytes = m.find() ? Long.valueOf(m.group(1)) : 0; +        memoryStat.rssInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;          m = CACHE_IN_BYTES.matcher(memoryStatContents); -        memoryStat.cacheInBytes = m.find() ? Long.valueOf(m.group(1)) : 0; +        memoryStat.cacheInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;          m = SWAP_IN_BYTES.matcher(memoryStatContents); -        memoryStat.swapInBytes = m.find() ? Long.valueOf(m.group(1)) : 0; +        memoryStat.swapInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;          return memoryStat;      } +    @VisibleForTesting +    static long parseMemoryMaxUsageFromMemCg(String memoryMaxUsageContents) { +        if (memoryMaxUsageContents == null || memoryMaxUsageContents.isEmpty()) { +            return 0; +        } +        try { +            return Long.parseLong(memoryMaxUsageContents); +        } catch (NumberFormatException e) { +            Slog.e(TAG, "Failed to parse value", e); +            return 0; +        } +    } +      /** -     * Parses relevant statistics out from the contents of a /proc/pid/stat file in procfs. +     * Parses relevant statistics out from the contents of the /proc/pid/stat file in procfs.       */ -    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) +    @VisibleForTesting      @Nullable      static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {          if (procStatContents == null || procStatContents.isEmpty()) { @@ -150,11 +187,30 @@ final class MemoryStatUtil {              return null;          } -        final MemoryStat memoryStat = new MemoryStat(); -        memoryStat.pgfault = Long.valueOf(splits[PGFAULT_INDEX]); -        memoryStat.pgmajfault = Long.valueOf(splits[PGMAJFAULT_INDEX]); -        memoryStat.rssInBytes = Long.valueOf(splits[RSS_IN_BYTES_INDEX]); -        return memoryStat; +        try { +            final MemoryStat memoryStat = new MemoryStat(); +            memoryStat.pgfault = Long.parseLong(splits[PGFAULT_INDEX]); +            memoryStat.pgmajfault = Long.parseLong(splits[PGMAJFAULT_INDEX]); +            memoryStat.rssInBytes = Long.parseLong(splits[RSS_IN_PAGES_INDEX]) * PAGE_SIZE; +            return memoryStat; +        } catch (NumberFormatException e) { +            Slog.e(TAG, "Failed to parse value", e); +            return null; +        } +    } + +    /** +     * Parses RSS high watermark out from the contents of the /proc/pid/status file in procfs. The +     * returned value is in bytes. +     */ +    @VisibleForTesting +    static long parseVmHWMFromProcfs(String procStatusContents) { +        if (procStatusContents == null || procStatusContents.isEmpty()) { +            return 0; +        } +        Matcher m = RSS_HIGH_WATERMARK_IN_BYTES.matcher(procStatusContents); +        // Convert value read from /proc/pid/status from kilobytes to bytes. +        return m.find() ? Long.parseLong(m.group(1)) * BYTES_IN_KILOBYTE : 0;      }      /** @@ -175,5 +231,7 @@ final class MemoryStatUtil {          long cacheInBytes;          /** Number of bytes of swap usage */          long swapInBytes; +        /** Number of bytes of peak anonymous and swap cache memory */ +        long rssHighWatermarkInBytes;      }  } diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java new file mode 100644 index 000000000000..a9c00a70650c --- /dev/null +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.app.Activity; +import android.app.ActivityManagerInternal; +import android.app.AppGlobals; +import android.app.PendingIntent; +import android.content.IIntentSender; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Slog; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for {@link ActivityManagerService} responsible for managing pending intents. + * + * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of + * {@link ActivityManagerService} lock since there can be direct calls into this class from outside + * AM. This helps avoid deadlocks. + */ +public class PendingIntentController { +    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; +    private static final String TAG_MU = TAG + POSTFIX_MU; + +    /** Lock for internal state. */ +    final Object mLock = new Object(); +    final Handler mH; +    ActivityManagerInternal mAmInternal; +    final UserController mUserController; +    final ActivityTaskManagerInternal mAtmInternal; + +    /** Set of IntentSenderRecord objects that are currently active. */ +    final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords +            = new HashMap<>(); + +    PendingIntentController(Looper looper, UserController userController) { +        mH = new Handler(looper); +        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); +        mUserController = userController; +    } + +    void onActivityManagerInternalAdded() { +        synchronized (mLock) { +            mAmInternal = LocalServices.getService(ActivityManagerInternal.class); +        } +    } + +    PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId, +            IBinder token, String resultWho, int requestCode, Intent[] intents, +            String[] resolvedTypes, int flags, Bundle bOptions) { +        synchronized (mLock) { +            if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid); + +            // We're going to be splicing together extras before sending, so we're +            // okay poking into any contained extras. +            if (intents != null) { +                for (int i = 0; i < intents.length; i++) { +                    intents[i].setDefusable(true); +                } +            } +            Bundle.setDefusable(bOptions, true); + +            final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; +            final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0; +            final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0; +            flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT +                    | PendingIntent.FLAG_UPDATE_CURRENT); + +            PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token, +                    resultWho, requestCode, intents, resolvedTypes, flags, +                    SafeActivityOptions.fromBundle(bOptions), userId); +            WeakReference<PendingIntentRecord> ref; +            ref = mIntentSenderRecords.get(key); +            PendingIntentRecord rec = ref != null ? ref.get() : null; +            if (rec != null) { +                if (!cancelCurrent) { +                    if (updateCurrent) { +                        if (rec.key.requestIntent != null) { +                            rec.key.requestIntent.replaceExtras(intents != null ? +                                    intents[intents.length - 1] : null); +                        } +                        if (intents != null) { +                            intents[intents.length - 1] = rec.key.requestIntent; +                            rec.key.allIntents = intents; +                            rec.key.allResolvedTypes = resolvedTypes; +                        } else { +                            rec.key.allIntents = null; +                            rec.key.allResolvedTypes = null; +                        } +                    } +                    return rec; +                } +                makeIntentSenderCanceled(rec); +                mIntentSenderRecords.remove(key); +            } +            if (noCreate) { +                return rec; +            } +            rec = new PendingIntentRecord(this, key, callingUid); +            mIntentSenderRecords.put(key, rec.ref); +            return rec; +        } +    } + +    boolean removePendingIntentsForPackage(String packageName, int userId, int appId, +            boolean doIt) { + +        boolean didSomething = false; +        synchronized (mLock) { + +            // Remove pending intents.  For now we only do this when force stopping users, because +            // we have some problems when doing this for packages -- app widgets are not currently +            // cleaned up for such packages, so they can be left with bad pending intents. +            if (mIntentSenderRecords.size() <= 0) { +                return false; +            } + +            Iterator<WeakReference<PendingIntentRecord>> it +                    = mIntentSenderRecords.values().iterator(); +            while (it.hasNext()) { +                WeakReference<PendingIntentRecord> wpir = it.next(); +                if (wpir == null) { +                    it.remove(); +                    continue; +                } +                PendingIntentRecord pir = wpir.get(); +                if (pir == null) { +                    it.remove(); +                    continue; +                } +                if (packageName == null) { +                    // Stopping user, remove all objects for the user. +                    if (pir.key.userId != userId) { +                        // Not the same user, skip it. +                        continue; +                    } +                } else { +                    if (UserHandle.getAppId(pir.uid) != appId) { +                        // Different app id, skip it. +                        continue; +                    } +                    if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { +                        // Different user, skip it. +                        continue; +                    } +                    if (!pir.key.packageName.equals(packageName)) { +                        // Different package, skip it. +                        continue; +                    } +                } +                if (!doIt) { +                    return true; +                } +                didSomething = true; +                it.remove(); +                makeIntentSenderCanceled(pir); +                if (pir.key.activity != null) { +                    final Message m = PooledLambda.obtainMessage( +                            PendingIntentController::clearPendingResultForActivity, this, +                            pir.key.activity, pir.ref); +                    mH.sendMessage(m); +                } +            } +        } + +        return didSomething; +    } + +    public void cancelIntentSender(IIntentSender sender) { +        if (!(sender instanceof PendingIntentRecord)) { +            return; +        } +        synchronized (mLock) { +            final PendingIntentRecord rec = (PendingIntentRecord) sender; +            try { +                final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, +                        MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); +                if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { +                    String msg = "Permission Denial: cancelIntentSender() from pid=" +                            + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() +                            + " is not allowed to cancel package " + rec.key.packageName; +                    Slog.w(TAG, msg); +                    throw new SecurityException(msg); +                } +            } catch (RemoteException e) { +                throw new SecurityException(e); +            } +            cancelIntentSender(rec, true); +        } +    } + +    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) { +        synchronized (mLock) { +            makeIntentSenderCanceled(rec); +            mIntentSenderRecords.remove(rec.key); +            if (cleanActivity && rec.key.activity != null) { +                final Message m = PooledLambda.obtainMessage( +                        PendingIntentController::clearPendingResultForActivity, this, +                        rec.key.activity, rec.ref); +                mH.sendMessage(m); +            } +        } +    } + +    private void makeIntentSenderCanceled(PendingIntentRecord rec) { +        rec.canceled = true; +        final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); +        if (callbacks != null) { +            final Message m = PooledLambda.obtainMessage( +                    PendingIntentController::handlePendingIntentCancelled, this, callbacks); +            mH.sendMessage(m); +        } +    } + +    private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) { +        int N = callbacks.beginBroadcast(); +        for (int i = 0; i < N; i++) { +            try { +                callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); +            } catch (RemoteException e) { +                // Process is not longer running...whatever. +            } +        } +        callbacks.finishBroadcast(); +        // We have to clean up the RemoteCallbackList here, because otherwise it will +        // needlessly hold the enclosed callbacks until the remote process dies. +        callbacks.kill(); +    } + +    private void clearPendingResultForActivity(IBinder activityToken, +            WeakReference<PendingIntentRecord> pir) { +        mAtmInternal.clearPendingResultForActivity(activityToken, pir); +    } + +    void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) { +        synchronized (mLock) { +            boolean printed = false; + +            pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); + +            if (mIntentSenderRecords.size() > 0) { +                // Organize these by package name, so they are easier to read. +                final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); +                final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); +                final Iterator<WeakReference<PendingIntentRecord>> it +                        = mIntentSenderRecords.values().iterator(); +                while (it.hasNext()) { +                    WeakReference<PendingIntentRecord> ref = it.next(); +                    PendingIntentRecord rec = ref != null ? ref.get() : null; +                    if (rec == null) { +                        weakRefs.add(ref); +                        continue; +                    } +                    if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { +                        continue; +                    } +                    ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); +                    if (list == null) { +                        list = new ArrayList<>(); +                        byPackage.put(rec.key.packageName, list); +                    } +                    list.add(rec); +                } +                for (int i = 0; i < byPackage.size(); i++) { +                    ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); +                    printed = true; +                    pw.print("  * "); pw.print(byPackage.keyAt(i)); +                    pw.print(": "); pw.print(intents.size()); pw.println(" items"); +                    for (int j = 0; j < intents.size(); j++) { +                        pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); +                        if (dumpAll) { +                            intents.get(j).dump(pw, "      "); +                        } +                    } +                } +                if (weakRefs.size() > 0) { +                    printed = true; +                    pw.println("  * WEAK REFS:"); +                    for (int i = 0; i < weakRefs.size(); i++) { +                        pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); +                    } +                } +            } + +            if (!printed) { +                pw.println("  (nothing)"); +            } +        } +    } +} diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index ee1166e2a6e8..b9c6fa6020c4 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -38,15 +38,16 @@ import android.util.Slog;  import android.util.TimeUtils;  import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda;  import java.io.PrintWriter;  import java.lang.ref.WeakReference;  import java.util.Objects; -final class PendingIntentRecord extends IIntentSender.Stub { +public final class PendingIntentRecord extends IIntentSender.Stub {      private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; -    final ActivityManagerService owner; +    final PendingIntentController controller;      final Key key;      final int uid;      final WeakReference<PendingIntentRecord> ref; @@ -62,7 +63,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {      final static class Key {          final int type;          final String packageName; -        final ActivityRecord activity; +        final IBinder activity;          final String who;          final int requestCode;          final Intent requestIntent; @@ -76,7 +77,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {          private static final int ODD_PRIME_NUMBER = 37; -        Key(int _t, String _p, ActivityRecord _a, String _w, +        Key(int _t, String _p, IBinder _a, String _w,                  int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {              type = _t;              packageName = _p; @@ -114,6 +115,7 @@ final class PendingIntentRecord extends IIntentSender.Stub {              //        + Integer.toHexString(hashCode));          } +        @Override          public boolean equals(Object otherObj) {              if (otherObj == null) {                  return false; @@ -188,11 +190,11 @@ final class PendingIntentRecord extends IIntentSender.Stub {          }      } -    PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { -        owner = _owner; +    PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) { +        controller = _controller;          key = _k;          uid = _u; -        ref = new WeakReference<PendingIntentRecord>(this); +        ref = new WeakReference<>(this);      }      void setWhitelistDurationLocked(IBinder whitelistToken, long duration) { @@ -247,189 +249,196 @@ final class PendingIntentRecord extends IIntentSender.Stub {      }      int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, -            IIntentReceiver finishedReceiver, -            String requiredPermission, IBinder resultTo, String resultWho, int requestCode, -            int flagsMask, int flagsValues, Bundle options) { +            IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, +            String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {          if (intent != null) intent.setDefusable(true);          if (options != null) options.setDefusable(true); -        synchronized (owner) { -            if (!canceled) { -                sent = true; -                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { -                    owner.cancelIntentSenderLocked(this, true); -                } +        Long duration = null; +        Intent finalIntent = null; +        Intent[] allIntents = null; +        String[] allResolvedTypes = null; +        SafeActivityOptions mergedOptions = null; +        synchronized (controller.mLock) { +            if (canceled) { +                return ActivityManager.START_CANCELED; +            } -                Intent finalIntent = key.requestIntent != null -                        ? new Intent(key.requestIntent) : new Intent(); +            sent = true; +            if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) { +                controller.cancelIntentSender(this, true); +            } -                final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; -                if (!immutable) { -                    if (intent != null) { -                        int changes = finalIntent.fillIn(intent, key.flags); -                        if ((changes & Intent.FILL_IN_DATA) == 0) { -                            resolvedType = key.requestResolvedType; -                        } -                    } else { +            finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); + +            final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; +            if (!immutable) { +                if (intent != null) { +                    int changes = finalIntent.fillIn(intent, key.flags); +                    if ((changes & Intent.FILL_IN_DATA) == 0) {                          resolvedType = key.requestResolvedType;                      } -                    flagsMask &= ~Intent.IMMUTABLE_FLAGS; -                    flagsValues &= flagsMask; -                    finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);                  } else {                      resolvedType = key.requestResolvedType;                  } +                flagsMask &= ~Intent.IMMUTABLE_FLAGS; +                flagsValues &= flagsMask; +                finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); +            } else { +                resolvedType = key.requestResolvedType; +            } -                final int callingUid = Binder.getCallingUid(); -                final int callingPid = Binder.getCallingPid(); +            // Extract options before clearing calling identity +            mergedOptions = key.options; +            if (mergedOptions == null) { +                mergedOptions = SafeActivityOptions.fromBundle(options); +            } else { +                mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); +            } -                // Extract options before clearing calling identity -                SafeActivityOptions mergedOptions = key.options; -                if (mergedOptions == null) { -                    mergedOptions = SafeActivityOptions.fromBundle(options); -                } else { -                    mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); +            if (whitelistDuration != null) { +                duration = whitelistDuration.get(whitelistToken); +            } + +            if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY +                    && key.allIntents != null && key.allIntents.length > 1) { +                // Copy all intents and resolved types while we have the controller lock so we can +                // use it later when the lock isn't held. +                allIntents = new Intent[key.allIntents.length]; +                allResolvedTypes = new String[key.allIntents.length]; +                System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length); +                if (key.allResolvedTypes != null) { +                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, +                            key.allResolvedTypes.length);                  } +                allIntents[allIntents.length - 1] = finalIntent; +                allResolvedTypes[allResolvedTypes.length - 1] = resolvedType; +            } -                final long origId = Binder.clearCallingIdentity(); - -                if (whitelistDuration != null) { -                    Long duration = whitelistDuration.get(whitelistToken); -                    if (duration != null) { -                        int procState = owner.getUidState(callingUid); -                        if (!ActivityManager.isProcStateBackground(procState)) { -                            StringBuilder tag = new StringBuilder(64); -                            tag.append("pendingintent:"); -                            UserHandle.formatUid(tag, callingUid); -                            tag.append(":"); -                            if (finalIntent.getAction() != null) { -                                tag.append(finalIntent.getAction()); -                            } else if (finalIntent.getComponent() != null) { -                                finalIntent.getComponent().appendShortString(tag); -                            } else if (finalIntent.getData() != null) { -                                tag.append(finalIntent.getData().toSafeString()); -                            } -                            owner.tempWhitelistForPendingIntentLocked(callingPid, -                                    callingUid, uid, duration, tag.toString()); -                        } else { -                            Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" -                                    + procState); -                        } +        } +        // We don't hold the controller lock beyond this point as we will be calling into AM and WM. + +        final int callingUid = Binder.getCallingUid(); +        final int callingPid = Binder.getCallingPid(); +        final long origId = Binder.clearCallingIdentity(); + +        int res = START_SUCCESS; +        try { +            if (duration != null) { +                int procState = controller.mAmInternal.getUidProcessState(callingUid); +                if (!ActivityManager.isProcStateBackground(procState)) { +                    StringBuilder tag = new StringBuilder(64); +                    tag.append("pendingintent:"); +                    UserHandle.formatUid(tag, callingUid); +                    tag.append(":"); +                    if (finalIntent.getAction() != null) { +                        tag.append(finalIntent.getAction()); +                    } else if (finalIntent.getComponent() != null) { +                        finalIntent.getComponent().appendShortString(tag); +                    } else if (finalIntent.getData() != null) { +                        tag.append(finalIntent.getData().toSafeString());                      } +                    controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid, +                            uid, duration, tag.toString()); +                } else { +                    Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" + procState);                  } +            } -                boolean sendFinish = finishedReceiver != null; -                int userId = key.userId; -                if (userId == UserHandle.USER_CURRENT) { -                    userId = owner.mUserController.getCurrentOrTargetUserId(); -                } -                int res = START_SUCCESS; -                switch (key.type) { -                    case ActivityManager.INTENT_SENDER_ACTIVITY: -                        try { -                            // Note when someone has a pending intent, even from different -                            // users, then there's no need to ensure the calling user matches -                            // the target user, so validateIncomingUser is always false below. - -                            if (key.allIntents != null && key.allIntents.length > 1) { -                                Intent[] allIntents = new Intent[key.allIntents.length]; -                                String[] allResolvedTypes = new String[key.allIntents.length]; -                                System.arraycopy(key.allIntents, 0, allIntents, 0, -                                        key.allIntents.length); -                                if (key.allResolvedTypes != null) { -                                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, -                                            key.allResolvedTypes.length); -                                } -                                allIntents[allIntents.length-1] = finalIntent; -                                allResolvedTypes[allResolvedTypes.length-1] = resolvedType; - -                                res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage( -                                        uid, key.packageName, allIntents, allResolvedTypes, -                                        resultTo, mergedOptions, userId, -                                        false /* validateIncomingUser */, -                                        this /* originatingPendingIntent */); -                            } else { -                                res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid, -                                        callingPid, callingUid, key.packageName, finalIntent, -                                        resolvedType, resultTo, resultWho, requestCode, 0, -                                        mergedOptions, userId, null, "PendingIntentRecord", -                                        false /* validateIncomingUser */, -                                        this /* originatingPendingIntent */); -                            } -                        } catch (RuntimeException e) { -                            Slog.w(TAG, "Unable to send startActivity intent", e); -                        } -                        break; -                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: -                        final ActivityStack stack = key.activity.getStack(); -                        if (stack != null) { -                            stack.sendActivityResultLocked(-1, key.activity, key.who, -                                    key.requestCode, code, finalIntent); -                        } -                        break; -                    case ActivityManager.INTENT_SENDER_BROADCAST: -                        try { -                            // If a completion callback has been requested, require -                            // that the broadcast be delivered synchronously -                            int sent = owner.broadcastIntentInPackage(key.packageName, uid, -                                    finalIntent, resolvedType, finishedReceiver, code, null, null, -                                    requiredPermission, options, (finishedReceiver != null), -                                    false, userId); -                            if (sent == ActivityManager.BROADCAST_SUCCESS) { -                                sendFinish = false; -                            } -                        } catch (RuntimeException e) { -                            Slog.w(TAG, "Unable to send startActivity intent", e); +            boolean sendFinish = finishedReceiver != null; +            int userId = key.userId; +            if (userId == UserHandle.USER_CURRENT) { +                userId = controller.mUserController.getCurrentOrTargetUserId(); +            } + +            switch (key.type) { +                case ActivityManager.INTENT_SENDER_ACTIVITY: +                    try { +                        // Note when someone has a pending intent, even from different +                        // users, then there's no need to ensure the calling user matches +                        // the target user, so validateIncomingUser is always false below. + +                        if (key.allIntents != null && key.allIntents.length > 1) { +                            res = controller.mAtmInternal.startActivitiesInPackage( +                                    uid, key.packageName, allIntents, allResolvedTypes, resultTo, +                                    mergedOptions, userId, false /* validateIncomingUser */, +                                    this /* originatingPendingIntent */); +                        } else { +                            res = controller.mAtmInternal.startActivityInPackage( +                                    uid, callingPid, callingUid, key.packageName, finalIntent, +                                    resolvedType, resultTo, resultWho, requestCode, 0, +                                    mergedOptions, userId, null, "PendingIntentRecord", +                                    false /* validateIncomingUser */, +                                    this /* originatingPendingIntent */);                          } -                        break; -                    case ActivityManager.INTENT_SENDER_SERVICE: -                    case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: -                        try { -                            owner.startServiceInPackage(uid, finalIntent, resolvedType, -                                    key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, -                                    key.packageName, userId); -                        } catch (RuntimeException e) { -                            Slog.w(TAG, "Unable to send startService intent", e); -                        } catch (TransactionTooLargeException e) { -                            res = ActivityManager.START_CANCELED; +                    } catch (RuntimeException e) { +                        Slog.w(TAG, "Unable to send startActivity intent", e); +                    } +                    break; +                case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: +                    controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who, +                                key.requestCode, code, finalIntent); +                    break; +                case ActivityManager.INTENT_SENDER_BROADCAST: +                    try { +                        // If a completion callback has been requested, require +                        // that the broadcast be delivered synchronously +                        int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName, +                                uid, finalIntent, resolvedType, finishedReceiver, code, null, null, +                                requiredPermission, options, (finishedReceiver != null), +                                false, userId); +                        if (sent == ActivityManager.BROADCAST_SUCCESS) { +                            sendFinish = false;                          } -                        break; -                } - -                if (sendFinish && res != ActivityManager.START_CANCELED) { +                    } catch (RuntimeException e) { +                        Slog.w(TAG, "Unable to send startActivity intent", e); +                    } +                    break; +                case ActivityManager.INTENT_SENDER_SERVICE: +                case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:                      try { -                        finishedReceiver.performReceive(new Intent(finalIntent), 0, -                                null, null, false, false, key.userId); -                    } catch (RemoteException e) { +                        controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType, +                                key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, +                                key.packageName, userId); +                    } catch (RuntimeException e) { +                        Slog.w(TAG, "Unable to send startService intent", e); +                    } catch (TransactionTooLargeException e) { +                        res = ActivityManager.START_CANCELED;                      } -                } - -                Binder.restoreCallingIdentity(origId); +                    break; +            } -                return res; +            if (sendFinish && res != ActivityManager.START_CANCELED) { +                try { +                    finishedReceiver.performReceive(new Intent(finalIntent), 0, +                            null, null, false, false, key.userId); +                } catch (RemoteException e) { +                }              } +        } finally { +            Binder.restoreCallingIdentity(origId);          } -        return ActivityManager.START_CANCELED; + +        return res;      }      @Override      protected void finalize() throws Throwable {          try {              if (!canceled) { -                owner.mHandler.sendMessage(owner.mHandler.obtainMessage( -                        ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); +                controller.mH.sendMessage(PooledLambda.obtainMessage( +                        PendingIntentRecord::completeFinalize, this));              }          } finally {              super.finalize();          }      } -    public void completeFinalize() { -        synchronized(owner) { -            WeakReference<PendingIntentRecord> current = -                    owner.mIntentSenderRecords.get(key); +    private void completeFinalize() { +        synchronized(controller.mLock) { +            WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key);              if (current == ref) { -                owner.mIntentSenderRecords.remove(key); +                controller.mIntentSenderRecords.remove(key);              }          }      } diff --git a/services/core/java/com/android/server/am/PersistentConnection.java b/services/core/java/com/android/server/am/PersistentConnection.java index c5edb26892f8..080fa2a2ec5e 100644 --- a/services/core/java/com/android/server/am/PersistentConnection.java +++ b/services/core/java/com/android/server/am/PersistentConnection.java @@ -24,7 +24,7 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.SystemClock;  import android.os.UserHandle; -import android.util.Slog; +import android.util.Log;  import android.util.TimeUtils;  import com.android.internal.annotations.GuardedBy; @@ -100,6 +100,15 @@ public abstract class PersistentConnection<T> {      @GuardedBy("mLock")      private T mService; +    @GuardedBy("mLock") +    private int mNumConnected; + +    @GuardedBy("mLock") +    private int mNumDisconnected; + +    @GuardedBy("mLock") +    private int mNumBindingDied; +      private final ServiceConnection mServiceConnection = new ServiceConnection() {          @Override          public void onServiceConnected(ComponentName name, IBinder service) { @@ -108,13 +117,15 @@ public abstract class PersistentConnection<T> {                      // Callback came in after PersistentConnection.unbind() was called.                      // We just ignore this.                      // (We've already called unbindService() already in unbind) -                    Slog.w(mTag, "Connected: " + mComponentName.flattenToShortString() +                    Log.w(mTag, "Connected: " + mComponentName.flattenToShortString()                              + " u" + mUserId + " but not bound, ignore.");                      return;                  } -                Slog.i(mTag, "Connected: " + mComponentName.flattenToShortString() +                Log.i(mTag, "Connected: " + mComponentName.flattenToShortString()                          + " u" + mUserId); +                mNumConnected++; +                  mIsConnected = true;                  mService = asInterface(service);              } @@ -123,9 +134,11 @@ public abstract class PersistentConnection<T> {          @Override          public void onServiceDisconnected(ComponentName name) {              synchronized (mLock) { -                Slog.i(mTag, "Disconnected: " + mComponentName.flattenToShortString() +                Log.i(mTag, "Disconnected: " + mComponentName.flattenToShortString()                          + " u" + mUserId); +                mNumDisconnected++; +                  cleanUpConnectionLocked();              }          } @@ -136,13 +149,16 @@ public abstract class PersistentConnection<T> {              synchronized (mLock) {                  if (!mBound) {                      // Callback came in late? -                    Slog.w(mTag, "Binding died: " + mComponentName.flattenToShortString() +                    Log.w(mTag, "Binding died: " + mComponentName.flattenToShortString()                              + " u" + mUserId + " but not bound, ignore.");                      return;                  } -                Slog.w(mTag, "Binding died: " + mComponentName.flattenToShortString() +                Log.w(mTag, "Binding died: " + mComponentName.flattenToShortString()                          + " u" + mUserId); + +                mNumBindingDied++; +                  scheduleRebindLocked();              }          } @@ -170,6 +186,12 @@ public abstract class PersistentConnection<T> {          return mComponentName;      } +    public final int getUserId() { +        return mUserId; +    } + +    protected abstract int getBindFlags(); +      /**       * @return whether {@link #bind()} has been called and {@link #unbind()} hasn't.       * @@ -237,15 +259,15 @@ public abstract class PersistentConnection<T> {          final Intent service = new Intent().setComponent(mComponentName);          if (DEBUG) { -            Slog.d(mTag, "Attempting to connect to " + mComponentName); +            Log.d(mTag, "Attempting to connect to " + mComponentName);          }          final boolean success = mContext.bindServiceAsUser(service, mServiceConnection, -                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, +                Context.BIND_AUTO_CREATE | getBindFlags(),                  mHandler, UserHandle.of(mUserId));          if (!success) { -            Slog.e(mTag, "Binding: " + service.getComponent() + " u" + mUserId +            Log.e(mTag, "Binding: " + service.getComponent() + " u" + mUserId                      + " failed.");          }      } @@ -285,7 +307,7 @@ public abstract class PersistentConnection<T> {          if (!mBound) {              return;          } -        Slog.i(mTag, "Stopping: " + mComponentName.flattenToShortString() + " u" + mUserId); +        Log.i(mTag, "Stopping: " + mComponentName.flattenToShortString() + " u" + mUserId);          mBound = false;          mContext.unbindService(mServiceConnection); @@ -303,7 +325,7 @@ public abstract class PersistentConnection<T> {          unbindLocked();          if (!mRebindScheduled) { -            Slog.i(mTag, "Scheduling to reconnect in " + mNextBackoffMs + " ms (uptime)"); +            Log.i(mTag, "Scheduling to reconnect in " + mNextBackoffMs + " ms (uptime)");              mReconnectTime = injectUptimeMillis() + mNextBackoffMs; @@ -323,10 +345,12 @@ public abstract class PersistentConnection<T> {          synchronized (mLock) {              pw.print(prefix);              pw.print(mComponentName.flattenToShortString()); -            pw.print(mBound ? "  [bound]" : "  [not bound]"); -            pw.print(mIsConnected ? "  [connected]" : "  [not connected]"); +            pw.print(" u"); +            pw.print(mUserId); +            pw.print(mBound ? " [bound]" : " [not bound]"); +            pw.print(mIsConnected ? " [connected]" : " [not connected]");              if (mRebindScheduled) { -                pw.print("  reconnect in "); +                pw.print(" reconnect in ");                  TimeUtils.formatDuration((mReconnectTime - injectUptimeMillis()), pw);              }              pw.println(); @@ -334,6 +358,16 @@ public abstract class PersistentConnection<T> {              pw.print(prefix);              pw.print("  Next backoff(sec): ");              pw.print(mNextBackoffMs / 1000); +            pw.println(); + +            pw.print(prefix); +            pw.print("  Connected: "); +            pw.print(mNumConnected); +            pw.print("  Disconnected: "); +            pw.print(mNumDisconnected); +            pw.print("  Died: "); +            pw.print(mNumBindingDied); +            pw.println();          }      } diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index 8ce650c1a514..6ffd8a9180ba 100644 --- a/services/core/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java @@ -23,8 +23,10 @@ import android.os.RemoteException;  import android.os.SystemClock;  import android.os.SystemProperties;  import android.service.procstats.ProcessStatsServiceDumpProto; +import android.text.format.DateFormat;  import android.util.ArrayMap;  import android.util.AtomicFile; +import android.util.Log;  import android.util.LongSparseArray;  import android.util.Slog;  import android.util.SparseArray; @@ -47,6 +49,7 @@ import java.io.IOException;  import java.io.InputStream;  import java.io.PrintWriter;  import java.util.ArrayList; +import java.util.Arrays;  import java.util.Collections;  import java.util.List;  import java.util.concurrent.locks.ReentrantLock; @@ -482,6 +485,23 @@ public final class ProcessStatsService extends IProcessStats.Stub {          return finalRes;      } +    static int parseSectionOptions(String optionsStr) { +        final String sep = ","; +        String[] sectionsStr = optionsStr.split(sep); +        if (sectionsStr.length == 0) { +            return ProcessStats.REPORT_ALL; +        } +        int res = 0; +        List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR); +        for (String sectionStr : sectionsStr) { +            int optionIndex = optionStrList.indexOf(sectionStr); +            if (optionIndex != -1) { +                res |= ProcessStats.OPTIONS[optionIndex]; +            } +        } +        return res; +    } +      public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {          mAm.mContext.enforceCallingOrSelfPermission(                  android.Manifest.permission.PACKAGE_USAGE_STATS, null); @@ -514,6 +534,95 @@ public final class ProcessStatsService extends IProcessStats.Stub {          return current.marshall();      } +    /** +     * Get stats committed after highWaterMarkMs +     * @param highWaterMarkMs Report stats committed after this time. +     * @param section Integer mask to indicage which sections to include in the stats. +     * @param doAggregate Whether to aggregate the stats or keep them separated. +     * @return List of proto binary of individual commit files or one that is merged from them. +     */ +    @Override +    public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate, +            List<ParcelFileDescriptor> committedStats) { +        mAm.mContext.enforceCallingOrSelfPermission( +                android.Manifest.permission.PACKAGE_USAGE_STATS, null); + +        ProcessStats mergedStats = new ProcessStats(false); +        long newHighWaterMark = highWaterMarkMs; +        mWriteLock.lock(); +        try { +            ArrayList<String> files = getCommittedFiles(0, false, true); +            if (files != null) { +                String highWaterMarkStr = +                        DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString(); +                ProcessStats stats = new ProcessStats(false); +                for (int i = files.size() - 1; i >= 0; i--) { +                    String fileName = files.get(i); +                    try { +                        String startTimeStr = fileName.substring( +                                fileName.lastIndexOf(STATE_FILE_PREFIX) +                                        + STATE_FILE_PREFIX.length(), +                                fileName.lastIndexOf(STATE_FILE_SUFFIX)); +                        if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) { +                            ParcelFileDescriptor pfd = ParcelFileDescriptor.open( +                                    new File(fileName), +                                    ParcelFileDescriptor.MODE_READ_ONLY); +                            InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); +                            stats.reset(); +                            stats.read(is); +                            is.close(); +                            if (stats.mTimePeriodStartClock > newHighWaterMark) { +                                newHighWaterMark = stats.mTimePeriodStartClock; +                            } +                            if (doAggregate) { +                                mergedStats.add(stats); +                            } else { +                                committedStats.add(protoToParcelFileDescriptor(stats, section)); +                            } +                            if (stats.mReadError != null) { +                                Log.w(TAG, "Failure reading process stats: " + stats.mReadError); +                                continue; +                            } +                        } +                    } catch (IOException e) { +                        Slog.w(TAG, "Failure opening procstat file " + fileName, e); +                    } catch (IndexOutOfBoundsException e) { +                        Slog.w(TAG, "Failure to read and parse commit file " + fileName, e); +                    } +                } +                if (doAggregate) { +                    committedStats.add(protoToParcelFileDescriptor(mergedStats, section)); +                } +                return newHighWaterMark; +            } +        } catch (IOException e) { +            Slog.w(TAG, "Failure opening procstat file", e); +        } finally { +            mWriteLock.unlock(); +        } +        return newHighWaterMark; +    } + +    private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) +            throws IOException { +        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); +        Thread thr = new Thread("ProcessStats pipe output") { +            public void run() { +                try { +                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); +                    final ProtoOutputStream proto = new ProtoOutputStream(fout); +                    stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section); +                    proto.flush(); +                    fout.close(); +                } catch (IOException e) { +                    Slog.w(TAG, "Failure writing pipe", e); +                } +            } +        }; +        thr.start(); +        return fds[0]; +    } +      public ParcelFileDescriptor getStatsOverTime(long minTime) {          mAm.mContext.enforceCallingOrSelfPermission(                  android.Manifest.permission.PACKAGE_USAGE_STATS, null); @@ -594,7 +703,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {      private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,              String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails, -            boolean dumpAll, boolean activeOnly) { +            boolean dumpAll, boolean activeOnly, int section) {          ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000                  - (ProcessStats.COMMIT_PERIOD/2));          if (pfd == null) { @@ -609,11 +718,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {              return;          }          if (isCompact) { -            stats.dumpCheckinLocked(pw, reqPackage); +            stats.dumpCheckinLocked(pw, reqPackage, section);          } else {              if (dumpDetails || dumpFullDetails) {                  stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, -                        activeOnly); +                        activeOnly, section);              } else {                  stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);              } @@ -643,6 +752,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {          pw.println("  --max: for -a, max num of historical batches to print.");          pw.println("  --active: only show currently active processes/services.");          pw.println("  --commit: commit current stats to disk and reset to start new stats."); +        pw.println("  --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all "); +        pw.println("    options can be combined to select desired stats");          pw.println("  --reset: reset current stats, without committing.");          pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");          pw.println("  --write: write current in-memory stats to disk."); @@ -696,6 +807,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {          int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};          boolean csvSepProcStats = true;          int[] csvProcStats = ProcessStats.ALL_PROC_STATES; +        int section = ProcessStats.REPORT_ALL;          if (args != null) {              for (int i=0; i<args.length; i++) {                  String arg = args[i]; @@ -814,13 +926,14 @@ public final class ProcessStatsService extends IProcessStats.Stub {                          pw.println("Process stats committed.");                          quit = true;                      } -                } else if ("--reset".equals(arg)) { -                    synchronized (mAm) { -                        mProcessStats.resetSafely(); -                        mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); -                        pw.println("Process stats reset."); -                        quit = true; +                } else if ("--section".equals(arg)) { +                    i++; +                    if (i >= args.length) { +                        pw.println("Error: argument required for --section"); +                        dumpHelp(pw); +                        return;                      } +                    section = parseSectionOptions(args[i]);                  } else if ("--clear".equals(arg)) {                      synchronized (mAm) {                          mProcessStats.resetSafely(); @@ -946,7 +1059,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {          } else if (aggregateHours != 0) {              pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");              dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact, -                    dumpDetails, dumpFullDetails, dumpAll, activeOnly); +                    dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);              return;          } else if (lastIndex > 0) {              pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":"); @@ -968,7 +1081,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {              boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);              if (isCheckin || isCompact) {                  // Don't really need to lock because we uniquely own this object. -                processStats.dumpCheckinLocked(pw, reqPackage); +                processStats.dumpCheckinLocked(pw, reqPackage, section);              } else {                  pw.print("COMMITTED STATS FROM ");                  pw.print(processStats.mTimePeriodStartClockStr); @@ -976,7 +1089,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {                  pw.println(":");                  if (dumpDetails || dumpFullDetails) {                      processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, -                            dumpAll, activeOnly); +                            dumpAll, activeOnly, section);                      if (dumpAll) {                          pw.print("  mFile="); pw.println(mFile.getBaseFile());                      } @@ -1015,7 +1128,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {                              boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);                              if (isCheckin || isCompact) {                                  // Don't really need to lock because we uniquely own this object. -                                processStats.dumpCheckinLocked(pw, reqPackage); +                                processStats.dumpCheckinLocked(pw, reqPackage, section);                              } else {                                  if (sepNeeded) {                                      pw.println(); @@ -1031,7 +1144,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {                                  // much crud.                                  if (dumpFullDetails) {                                      processStats.dumpLocked(pw, reqPackage, now, false, false, -                                            false, activeOnly); +                                            false, activeOnly, section);                                  } else {                                      processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);                                  } @@ -1054,7 +1167,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {          if (!isCheckin) {              synchronized (mAm) {                  if (isCompact) { -                    mProcessStats.dumpCheckinLocked(pw, reqPackage); +                    mProcessStats.dumpCheckinLocked(pw, reqPackage, section);                  } else {                      if (sepNeeded) {                          pw.println(); @@ -1062,7 +1175,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {                      pw.println("CURRENT STATS:");                      if (dumpDetails || dumpFullDetails) {                          mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, -                                dumpAll, activeOnly); +                                dumpAll, activeOnly, section);                          if (dumpAll) {                              pw.print("  mFile="); pw.println(mFile.getBaseFile());                          } @@ -1078,11 +1191,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {                  }                  pw.println("AGGREGATED OVER LAST 24 HOURS:");                  dumpAggregatedStats(pw, 24, now, reqPackage, isCompact, -                        dumpDetails, dumpFullDetails, dumpAll, activeOnly); +                        dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);                  pw.println();                  pw.println("AGGREGATED OVER LAST 3 HOURS:");                  dumpAggregatedStats(pw, 3, now, reqPackage, isCompact, -                        dumpDetails, dumpFullDetails, dumpAll, activeOnly); +                        dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);              }          }      } @@ -1099,7 +1212,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {          if (stats.mReadError != null) {              return;          } -        stats.writeToProto(proto, fieldId, now); +        final long token = proto.start(fieldId); +        stats.writeToProto(proto, now, ProcessStats.REPORT_ALL); +        proto.end(token);      }      private void dumpProto(FileDescriptor fd) { @@ -1109,7 +1224,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {          long now;          synchronized (mAm) {              now = SystemClock.uptimeMillis(); -            mProcessStats.writeToProto(proto,ProcessStatsServiceDumpProto.PROCSTATS_NOW, now); +            final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW); +            mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL); +            proto.end(token);          }          // aggregated over last 3 hours procstats diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java index f7de7f475b7b..fa0cb47ade02 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -44,7 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;   * the inner options. Also supports having two set of options: Once from the original caller, and   * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}.   */ -class SafeActivityOptions { +public class SafeActivityOptions {      private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 9b42d65483df..ef8cb1c07969 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -129,7 +129,8 @@ import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList;  import java.util.Objects; -class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { +// TODO: Make package private again once move to WM package is complete. +public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {      private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;      private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;      private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; diff --git a/services/core/java/com/android/server/appbinding/AppBindingConstants.java b/services/core/java/com/android/server/appbinding/AppBindingConstants.java new file mode 100644 index 000000000000..c2655a289b49 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/AppBindingConstants.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.appbinding; + +import android.util.KeyValueListParser; +import android.util.Slog; + +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +/** + * Constants that are configurable via the global settings for {@link AppBindingService}. + */ +class AppBindingConstants { +    private static final String TAG = AppBindingService.TAG; + +    private static final String SERVICE_RECONNECT_BACKOFF_SEC_KEY = +            "service_reconnect_backoff_sec"; + +    private static final String SERVICE_RECONNECT_BACKOFF_INCREASE_KEY = +            "service_reconnect_backoff_increase"; + +    private static final String SERVICE_RECONNECT_MAX_BACKOFF_SEC_KEY = +            "service_reconnect_max_backoff_sec"; + +    public final String sourceSettings; + +    /** +     * The back-off before re-connecting, when a service binding died, due to the app +     * crashing repeatedly. +     */ +    public final long SERVICE_RECONNECT_BACKOFF_SEC; + +    /** +     * The exponential back-off increase factor when a binding dies multiple times. +     */ +    public final double SERVICE_RECONNECT_BACKOFF_INCREASE; + +    /** +     * The max back-off +     */ +    public final long SERVICE_RECONNECT_MAX_BACKOFF_SEC; + +    private AppBindingConstants(String settings) { +        sourceSettings = settings; + +        final KeyValueListParser parser = new KeyValueListParser(','); +        try { +            parser.setString(settings); +        } catch (IllegalArgumentException e) { +            // Failed to parse the settings string, log this and move on +            // with defaults. +            Slog.e(TAG, "Bad setting: " + settings); +        } + +        long serviceReconnectBackoffSec = parser.getLong( +                SERVICE_RECONNECT_BACKOFF_SEC_KEY, TimeUnit.HOURS.toSeconds(1)); + +        double serviceReconnectBackoffIncrease = parser.getFloat( +                SERVICE_RECONNECT_BACKOFF_INCREASE_KEY, 2f); + +        long serviceReconnectMaxBackoffSec = parser.getLong( +                SERVICE_RECONNECT_MAX_BACKOFF_SEC_KEY, TimeUnit.DAYS.toSeconds(1)); + +        // Set minimum: 5 seconds. +        serviceReconnectBackoffSec = Math.max(5, serviceReconnectBackoffSec); + +        // Set minimum: 1.0. +        serviceReconnectBackoffIncrease = +                Math.max(1, serviceReconnectBackoffIncrease); + +        // Make sure max >= default back off. +        serviceReconnectMaxBackoffSec = Math.max(serviceReconnectBackoffSec, +                serviceReconnectMaxBackoffSec); + +        SERVICE_RECONNECT_BACKOFF_SEC = serviceReconnectBackoffSec; +        SERVICE_RECONNECT_BACKOFF_INCREASE = serviceReconnectBackoffIncrease; +        SERVICE_RECONNECT_MAX_BACKOFF_SEC = serviceReconnectMaxBackoffSec; +    } + +    /** +     * Create a new instance from a settings string. +     */ +    public static AppBindingConstants initializeFromString(String settings) { +        return new AppBindingConstants(settings); +    } + +    /** +     * dumpsys support. +     */ +    public void dump(String prefix, PrintWriter pw) { +        pw.print(prefix); +        pw.println("Constants:"); + +        pw.print(prefix); +        pw.print("  SERVICE_RECONNECT_BACKOFF_SEC: "); +        pw.println(SERVICE_RECONNECT_BACKOFF_SEC); + +        pw.print(prefix); +        pw.print("  SERVICE_RECONNECT_BACKOFF_INCREASE: "); +        pw.println(SERVICE_RECONNECT_BACKOFF_INCREASE); + +        pw.print(prefix); +        pw.print("  SERVICE_RECONNECT_MAX_BACKOFF_SEC: "); +        pw.println(SERVICE_RECONNECT_MAX_BACKOFF_SEC); +    } +} diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java new file mode 100644 index 000000000000..c5cb2a4f5814 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/AppBindingService.java @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appbinding; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppGlobals; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.IPackageManager; +import android.content.pm.ServiceInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.IInterface; +import android.os.UserHandle; +import android.provider.Settings; +import android.provider.Settings.Global; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.DumpUtils; +import com.android.server.SystemService; +import com.android.server.am.PersistentConnection; +import com.android.server.appbinding.finders.AppServiceFinder; +import com.android.server.appbinding.finders.SmsAppServiceFinder; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.function.Consumer; + +/** + * System server that keeps a binding to an app to keep it always running. + * + * <p>As of android Q, we only use it for the default SMS app. + * + * TODO Unit tests + * TODO How do we handle force stop?? + * TODO Change OOM adjustment to 200 or so + * TODO Only allow it when the service is associated with a secondary process. + */ +public class AppBindingService extends Binder { +    public static final String TAG = "AppBindingService"; + +    public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE + +    private final Object mLock = new Object(); + +    private final Injector mInjector; +    private final Context mContext; +    private final Handler mHandler; +    private final IPackageManager mIPackageManager; + +    @GuardedBy("mLock") +    private AppBindingConstants mConstants; + +    @GuardedBy("mLock") +    private final SparseBooleanArray mRunningUsers = new SparseBooleanArray(2); + +    @GuardedBy("mLock") +    private final ArrayList<AppServiceFinder> mApps = new ArrayList<>(); + +    @GuardedBy("mLock") +    private final ArrayList<AppServiceConnection> mConnections = new ArrayList<>(); + +    static class Injector { +        public IPackageManager getIPackageManager() { +            return AppGlobals.getPackageManager(); +        } +    } + +    /** +     * {@link SystemService} for this service. +     */ +    public static final class Lifecycle extends SystemService { +        final AppBindingService mService; + +        public Lifecycle(Context context) { +            super(context); +            mService = new AppBindingService(new Injector(), context); +        } + +        @Override +        public void onStart() { +            publishBinderService(Context.APP_BINDING_SERVICE, mService); +        } + +        @Override +        public void onBootPhase(int phase) { +            mService.onBootPhase(phase); +        } + +        @Override +        public void onStartUser(int userHandle) { +            mService.onStartUser(userHandle); +        } + +        @Override +        public void onUnlockUser(int userId) { +            mService.onUnlockUser(userId); +        } + +        @Override +        public void onStopUser(int userHandle) { +            mService.onStopUser(userHandle); +        } +    } + +    private AppBindingService(Injector injector, Context context) { +        mInjector = injector; +        mContext = context; + +        mIPackageManager = injector.getIPackageManager(); + +        mHandler = BackgroundThread.getHandler(); +        mApps.add(new SmsAppServiceFinder(context, this::onAppChanged, mHandler)); + +        // Initialize with the default value to make it non-null. +        mConstants = AppBindingConstants.initializeFromString(""); +    } + +    private void forAllAppsLocked(Consumer<AppServiceFinder> consumer) { +        for (int i = 0; i < mApps.size(); i++) { +            consumer.accept(mApps.get(i)); +        } +    } + +    private void onBootPhase(int phase) { +        if (DEBUG) { +            Slog.d(TAG, "onBootPhase: " + phase); +        } +        switch (phase) { +            case SystemService.PHASE_ACTIVITY_MANAGER_READY: +                onPhaseActivityManagerReady(); +                break; +            case SystemService.PHASE_THIRD_PARTY_APPS_CAN_START: +                onPhaseThirdPartyAppsCanStart(); +                break; +        } +    } + +    /** +     * Handle boot phase PHASE_ACTIVITY_MANAGER_READY. +     */ +    private void onPhaseActivityManagerReady() { +        final IntentFilter packageFilter = new IntentFilter(); +        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); +        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); +        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); +        packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); +        packageFilter.addDataScheme("package"); + +        packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); +        mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL, +                packageFilter, null, mHandler); + +        final IntentFilter userFilter = new IntentFilter(); +        userFilter.addAction(Intent.ACTION_USER_REMOVED); +        mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL, +                userFilter, null, mHandler); + +        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( +                Settings.Global.APP_BINDING_CONSTANTS), false, mSettingsObserver); + +        refreshConstants(); +    } + +    private final ContentObserver mSettingsObserver = new ContentObserver(null) { +        @Override +        public void onChange(boolean selfChange) { +            refreshConstants(); +        } +    }; + +    private void refreshConstants() { +        final String newSetting = Settings.Global.getString( +                mContext.getContentResolver(), Global.APP_BINDING_CONSTANTS); + +        synchronized (mLock) { +            if (TextUtils.equals(mConstants.sourceSettings, newSetting)) { +                return; +            } +            Slog.i(TAG, "Updating constants with: " + newSetting); +            mConstants = AppBindingConstants.initializeFromString(newSetting); + +            rebindAllLocked("settings update"); +        } +    } + +    @VisibleForTesting +    final BroadcastReceiver mPackageUserMonitor = new BroadcastReceiver() { +        @Override +        public void onReceive(Context context, Intent intent) { +            final int userId  = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); +            if (userId == UserHandle.USER_NULL) { +                Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); +                return; +            } + +            final String action = intent.getAction(); + +            if (Intent.ACTION_USER_REMOVED.equals(action)) { +                onUserRemoved(userId); +                return; +            } + +            final Uri intentUri = intent.getData(); +            final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() +                    : null; +            if (packageName == null) { +                Slog.w(TAG, "Intent broadcast does not contain package name: " + intent); +                return; +            } + +            final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + +            switch (action) { +                case Intent.ACTION_PACKAGE_ADDED: +                    if (replacing) { +                        handlePackageAddedReplacing(packageName, userId); +                    } +                    break; +                case Intent.ACTION_PACKAGE_REMOVED: +                    if (!replacing) { +                        handlePackageRemoved(packageName, userId); +                    } +                    break; +                case Intent.ACTION_PACKAGE_CHANGED: +                    handlePackageChanged(packageName, userId); +                    break; +            } +        } +    }; + +    /** +     * Handle boot phase PHASE_THIRD_PARTY_APPS_CAN_START. +     */ +    private void onPhaseThirdPartyAppsCanStart() { +        synchronized (mLock) { +            forAllAppsLocked(AppServiceFinder::startMonitoring); +        } +    } + +    /** User lifecycle callback. */ +    private void onStartUser(int userId) { +        if (DEBUG) { +            Slog.d(TAG, "onStartUser: u" + userId); +        } +        synchronized (mLock) { +            mRunningUsers.append(userId, true); +            bindServicesLocked(userId, null, "user start"); +        } +    } + +    /** User lifecycle callback. */ +    private void onUnlockUser(int userId) { +        if (DEBUG) { +            Slog.d(TAG, "onUnlockUser: u" + userId); +        } +        synchronized (mLock) { +            bindServicesLocked(userId, null, "user unlock"); +        } +    } + +    /** User lifecycle callback. */ +    private void onStopUser(int userId) { +        if (DEBUG) { +            Slog.d(TAG, "onStopUser: u" + userId); +        } +        synchronized (mLock) { +            unbindServicesLocked(userId, null, "user stop"); + +            mRunningUsers.delete(userId); +        } +    } + +    private void onUserRemoved(int userId) { +        if (DEBUG) { +            Slog.d(TAG, "onUserRemoved: u" + userId); +        } +        synchronized (mLock) { +            forAllAppsLocked((app) -> app.onUserRemoved(userId)); + +            mRunningUsers.delete(userId); +        } +    } + +    /** +     * Called when a target package changes; e.g. when the user changes the default SMS app. +     */ +    private void onAppChanged(AppServiceFinder finder, int userId) { +        if (DEBUG) { +            Slog.d(TAG, "onAppChanged: u" + userId + " " + finder.getAppDescription()); +        } +        synchronized (mLock) { +            final String reason = finder.getAppDescription() + " changed"; +            unbindServicesLocked(userId, finder, reason); +            bindServicesLocked(userId, finder, reason); +        } +    } + +    @Nullable +    private AppServiceFinder findFinderLocked(int userId, @NonNull String packageName) { +        for (int i = 0; i < mApps.size(); i++) { +            final AppServiceFinder app = mApps.get(i); +            if (packageName.equals(app.getTargetPackage(userId))) { +                return app; +            } +        } +        return null; +    } + +    @Nullable +    private AppServiceConnection findConnectionLock( +            int userId, @NonNull AppServiceFinder target) { +        for (int i = 0; i < mConnections.size(); i++) { +            final AppServiceConnection conn = mConnections.get(i); +            if ((conn.getUserId() == userId) && (conn.getFinder() == target)) { +                return conn; +            } +        } +        return null; +    } + +    private void handlePackageAddedReplacing(String packageName, int userId) { +        if (DEBUG) { +            Slog.d(TAG, "handlePackageAddedReplacing: u" + userId + " " + packageName); +        } +        synchronized (mLock) { +            final AppServiceFinder finder = findFinderLocked(userId, packageName); +            if (finder != null) { +                unbindServicesLocked(userId, finder, "package update"); +                bindServicesLocked(userId, finder, "package update"); +            } +        } +    } + +    private void handlePackageRemoved(String packageName, int userId) { +        if (DEBUG) { +            Slog.d(TAG, "handlePackageRemoved: u" + userId + " " + packageName); +        } +        synchronized (mLock) { +            final AppServiceFinder finder = findFinderLocked(userId, packageName); +            if (finder != null) { +                unbindServicesLocked(userId, finder, "package uninstall"); +            } +        } +    } + +    private void handlePackageChanged(String packageName, int userId) { +        if (DEBUG) { +            Slog.d(TAG, "handlePackageChanged: u" + userId + " " + packageName); +        } +        synchronized (mLock) { +            final AppServiceFinder finder = findFinderLocked(userId, packageName); +            if (finder != null) { +                unbindServicesLocked(userId, finder, "package changed"); +                bindServicesLocked(userId, finder, "package changed"); +            } +        } +    } + +    private void rebindAllLocked(String reason) { +        for (int i = 0; i < mRunningUsers.size(); i++) { +            if (!mRunningUsers.valueAt(i)) { +                continue; +            } +            final int userId = mRunningUsers.keyAt(i); + +            unbindServicesLocked(userId, null, reason); +            bindServicesLocked(userId, null, reason); +        } +    } + +    private void bindServicesLocked(int userId, @Nullable AppServiceFinder target, +            @NonNull String reasonForLog) { +        for (int i = 0; i < mApps.size(); i++) { +            final AppServiceFinder app = mApps.get(i); +            if (target != null && target != app) { +                continue; +            } + +            // Disconnect from existing binding. +            final AppServiceConnection existingConn = findConnectionLock(userId, app); +            if (existingConn != null) { +                unbindServicesLocked(userId, target, reasonForLog); +            } + +            final ServiceInfo service = app.findService(userId, mIPackageManager); +            if (service == null) { +                continue; +            } +            if (DEBUG) { +                Slog.d(TAG, "bindServicesLocked: u" + userId + " " + app.getAppDescription() +                        + " binding " + service.getComponentName() + " for " + reasonForLog); +            } +            final AppServiceConnection conn = +                    new AppServiceConnection(mContext, userId, mConstants, mHandler, +                            app, service.getComponentName()); +            mConnections.add(conn); +            conn.bind(); +        } +    } + +    private void unbindServicesLocked(int userId, @Nullable AppServiceFinder target, +            @NonNull String reasonForLog) { +        for (int i = mConnections.size() - 1; i >= 0; i--) { +            final AppServiceConnection conn = mConnections.get(i); +            if ((conn.getUserId() != userId) +                    || (target != null && conn.getFinder() != target)) { +                continue; +            } +            if (DEBUG) { +                Slog.d(TAG, "unbindServicesLocked: u" + userId +                        + " " + conn.getFinder().getAppDescription() +                        + " unbinding " + conn.getComponentName() + " for " + reasonForLog); +            } +            mConnections.remove(i); +            conn.unbind(); +        } +    } + +    private static class AppServiceConnection extends PersistentConnection<IInterface> { +        private final AppBindingConstants mConstants; +        private final AppServiceFinder mFinder; + +        AppServiceConnection(Context context, int userId, AppBindingConstants constants, +                Handler handler, AppServiceFinder finder, +                @NonNull ComponentName componentName) { +            super(TAG, context, handler, userId, componentName, +                    constants.SERVICE_RECONNECT_BACKOFF_SEC, +                    constants.SERVICE_RECONNECT_BACKOFF_INCREASE, +                    constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC); +            mFinder = finder; +            mConstants = constants; +        } + +        @Override +        protected int getBindFlags() { +            return Context.BIND_FOREGROUND_SERVICE; +        } + +        @Override +        protected IInterface asInterface(IBinder obj) { +            return mFinder.asInterface(obj); +        } + +        public AppServiceFinder getFinder() { +            return mFinder; +        } +    } + +    @Override +    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { +        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + +        if (args.length > 0 && "-s".equals(args[0])) { +            dumpSimple(pw); +            return; +        } + +        synchronized (mLock) { +            mConstants.dump("  ", pw); + +            pw.println(); +            pw.print("  Running users:"); +            for (int i = 0; i < mRunningUsers.size(); i++) { +                if (mRunningUsers.valueAt(i)) { +                    pw.print(" "); +                    pw.print(mRunningUsers.keyAt(i)); +                } +            } + +            pw.println(); +            pw.println("  Connections:"); +            for (int i = 0; i < mConnections.size(); i++) { +                final AppServiceConnection conn = mConnections.get(i); +                pw.print("    App type: "); +                pw.print(conn.getFinder().getAppDescription()); +                pw.println(); + +                conn.dump("      ", pw); +            } +            if (mConnections.size() == 0) { +                pw.println("    None:"); +            } + +            pw.println(); +            pw.println("  Finders:"); +            forAllAppsLocked((app) -> app.dump("    ", pw)); +        } +    } + +    /** +     * Print simple output for CTS. +     */ +    private void dumpSimple(PrintWriter pw) { +        synchronized (mLock) { +            for (int i = 0; i < mConnections.size(); i++) { +                final AppServiceConnection conn = mConnections.get(i); + +                pw.print("conn,"); +                pw.print(conn.getFinder().getAppDescription()); +                pw.print(","); +                pw.print(conn.getUserId()); +                pw.print(","); +                pw.print(conn.getComponentName().getPackageName()); +                pw.print(","); +                pw.print(conn.getComponentName().getClassName()); +                pw.print(","); +                pw.print(conn.isBound() ? "bound" : "not-bound"); +                pw.print(","); +                pw.print(conn.isConnected() ? "connected" : "not-connected"); +                pw.println(); +            } +            forAllAppsLocked((app) -> app.dumpSimple(pw)); +        } +    } +} diff --git a/services/core/java/com/android/server/appbinding/AppBindingUtils.java b/services/core/java/com/android/server/appbinding/AppBindingUtils.java new file mode 100644 index 000000000000..fcbaecf7e059 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/AppBindingUtils.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appbinding; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.RemoteException; +import android.util.Log; + +import java.util.List; + +/** + * Utility class to find a persistent bound service within an app. + */ +public class AppBindingUtils { +    private static final String TAG = "AppBindingUtils"; +    private AppBindingUtils() { +    } + +    /** +     * Find a service with the action {@code serviceAction} in the package {@code packageName}. +     * Returns null in any of the following cases. +     * - No service with the action is found. +     * - More than 1 service with the action is found. +     * - Found service is not protected with the permission {@code servicePermission}. +     */ +    @Nullable +    public static ServiceInfo findService(@NonNull String packageName, int userId, +            String serviceAction, String servicePermission, +            Class<?> serviceClassForLogging, +            IPackageManager ipm, +            StringBuilder errorMessage) { +        final String simpleClassName = serviceClassForLogging.getSimpleName(); +        final Intent intent = new Intent(serviceAction); +        intent.setPackage(packageName); + +        errorMessage.setLength(0); // Clear it. +        try { +            final ParceledListSlice<ResolveInfo> pls = ipm +                    .queryIntentServices(intent, null, /* flags=*/ 0, userId); +            if (pls == null || pls.getList().size() == 0) { +                errorMessage.append("Service with " + serviceAction + " not found."); +                return null; +            } +            final List<ResolveInfo> list = pls.getList(); +            // Note if multiple services are found, that's an error, even if only one of them +            // is exported. +            if (list.size() > 1) { +                errorMessage.append("More than one " + simpleClassName + "'s found in package " +                                + packageName + ".  They'll all be ignored."); +                Log.e(TAG, errorMessage.toString()); +                return null; +            } +            final ServiceInfo si = list.get(0).serviceInfo; + +            if (!servicePermission.equals(si.permission)) { +                errorMessage.append(simpleClassName + " " +                        + si.getComponentName().flattenToShortString() +                        + " must be protected with " + servicePermission +                        + "."); +                Log.e(TAG, errorMessage.toString()); +                return null; +            } +            return si; +        } catch (RemoteException e) { +            // Shouldn't happen +        } +        return null; +    } +} diff --git a/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java new file mode 100644 index 000000000000..68c5e496cc32 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appbinding.finders; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.pm.IPackageManager; +import android.content.pm.ServiceInfo; +import android.os.Handler; +import android.os.IBinder; +import android.os.IInterface; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.appbinding.AppBindingService; +import com.android.server.appbinding.AppBindingUtils; + +import java.io.PrintWriter; +import java.util.function.BiConsumer; + +/** + * Baseclss that finds "persistent" service from a type of an app. + * + * @param <TServiceType> Type of the target service class. + * @param <TServiceInterfaceType> Type of the IInterface class used by TServiceType. + */ +public abstract class AppServiceFinder<TServiceType, TServiceInterfaceType extends IInterface> { +    protected static final String TAG = AppBindingService.TAG; +    protected static final boolean DEBUG = AppBindingService.DEBUG; + +    protected final Context mContext; +    protected final BiConsumer<AppServiceFinder, Integer> mListener; +    protected final Handler mHandler; + +    private final Object mLock = new Object(); + +    @GuardedBy("mLock") +    private final SparseArray<String> mTargetPackages = new SparseArray(1); + +    @GuardedBy("mLock") +    private final SparseArray<ServiceInfo> mTargetServices = new SparseArray(1); + +    @GuardedBy("mLock") +    private final SparseArray<String> mLastMessages = new SparseArray(1); + +    public AppServiceFinder(Context context, +            BiConsumer<AppServiceFinder, Integer> listener, +            Handler callbackHandler) { +        mContext = context; +        mListener = listener; +        mHandler = callbackHandler; +    } + +    /** Human readable description of the type of apps; e.g. [Default SMS app] */ +    @NonNull +    public abstract String getAppDescription(); + +    /** Start monitoring apps. (e.g. Start watching the default SMS app changes.) */ +    public void startMonitoring() { +    } + +    /** Called when a user is removed. */ +    public void onUserRemoved(int userId) { +        synchronized (mLock) { +            mTargetPackages.delete(userId); +            mTargetServices.delete(userId); +        } +    } + +    /** +     * Find the target service from the target app on a given user. +     */ +    @Nullable +    public final ServiceInfo findService(int userId, IPackageManager ipm) { +        synchronized (mLock) { +            mTargetPackages.put(userId, null); +            mTargetServices.put(userId, null); + +            final String targetPackage = getTargetPackage(userId); +            if (DEBUG) { +                Slog.d(TAG, getAppDescription() + " package=" + targetPackage); +            } +            if (targetPackage == null) { +                final String message = "Target package not found"; +                mLastMessages.put(userId, message); +                Slog.w(TAG, getAppDescription() + " u" + userId + " " + message); +                return null; +            } +            mTargetPackages.put(userId, targetPackage); + +            final StringBuilder errorMessage = new StringBuilder(); +            final ServiceInfo service = AppBindingUtils.findService( +                    targetPackage, +                    userId, +                    getServiceAction(), +                    getServicePermission(), +                    getServiceClass(), +                    ipm, +                    errorMessage); + +            if (service == null) { +                final String message = errorMessage.toString(); +                mLastMessages.put(userId, message); +                if (DEBUG) { +                    Slog.w(TAG, getAppDescription() + " package " + targetPackage + " u" + userId +                            + " " + message); +                } +                return null; +            } + +            final String message = "Valid service found"; +            mLastMessages.put(userId, message); +            mTargetServices.put(userId, service); +            return service; +        } +    } + +    protected abstract Class<TServiceType> getServiceClass(); + +    /** +     * Convert a binder reference to a service interface type. +     */ +    public abstract TServiceInterfaceType asInterface(IBinder obj); + +    /** +     * @return the target package on a given user. +     */ +    @Nullable +    public abstract String getTargetPackage(int userId); + +    /** +     * @return the intent action that identifies the target service in the target app. +     */ +    @NonNull +    protected abstract String getServiceAction(); + +    /** +     * @return the permission that the target service must be protected with. +     */ +    @NonNull +    protected abstract String getServicePermission(); + +    /** Dumpsys support. */ +    public void dump(String prefix, PrintWriter pw) { +        pw.print(prefix); +        pw.print("App type: "); +        pw.print(getAppDescription()); +        pw.println(); + +        synchronized (mLock) { +            for (int i = 0; i < mTargetPackages.size(); i++) { +                pw.print(prefix); +                pw.print("  User: "); +                pw.print(mTargetPackages.keyAt(i)); +                pw.println(); + +                pw.print(prefix); +                pw.print("    Package: "); +                pw.print(mTargetPackages.valueAt(i)); +                pw.println(); + +                pw.print(prefix); +                pw.print("    Service: "); +                pw.print(mTargetServices.valueAt(i)); +                pw.println(); + +                pw.print(prefix); +                pw.print("    Message: "); +                pw.print(mLastMessages.valueAt(i)); +                pw.println(); +            } +        } +    } + +    /** Dumpys support */ +    public void dumpSimple(PrintWriter pw) { +        synchronized (mLock) { +            for (int i = 0; i < mTargetPackages.size(); i++) { +                pw.print("finder,"); +                pw.print(getAppDescription()); +                pw.print(","); +                pw.print(mTargetPackages.keyAt(i)); // User-id +                pw.print(","); +                pw.print(mTargetPackages.valueAt(i)); +                pw.print(","); +                pw.print(mTargetServices.valueAt(i)); +                pw.print(","); +                pw.print(mLastMessages.valueAt(i)); +                pw.println(); +            } +        } +    } +} diff --git a/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java new file mode 100644 index 000000000000..c908bd919748 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appbinding.finders; + +import static android.provider.Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL; + +import android.Manifest.permission; +import android.app.ISmsAppService; +import android.app.SmsAppService; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.IBinder; +import android.os.UserHandle; +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.SmsApplication; + +import java.util.function.BiConsumer; + +/** + * Find the SmsAppService service within the default SMS app. + */ +public class SmsAppServiceFinder extends AppServiceFinder<SmsAppService, ISmsAppService> { +    public SmsAppServiceFinder(Context context, +            BiConsumer<AppServiceFinder, Integer> listener, +            Handler callbackHandler) { +        super(context, listener, callbackHandler); +    } + +    @Override +    public String getAppDescription() { +        return "[Default SMS app]"; +    } + +    @Override +    protected Class<SmsAppService> getServiceClass() { +        return SmsAppService.class; +    } + +    @Override +    public ISmsAppService asInterface(IBinder obj) { +        return ISmsAppService.Stub.asInterface(obj); +    } + +    @Override +    protected String getServiceAction() { +        return TelephonyManager.ACTION_SMS_APP_SERVICE; +    } + +    @Override +    protected String getServicePermission() { +        return permission.BIND_SMS_APP_SERVICE; +    } + +    @Override +    public String getTargetPackage(int userId) { +        final ComponentName cn = SmsApplication.getDefaultSmsApplicationAsUser( +                mContext, /* updateIfNeeded= */ true, userId); +        return cn == null ? null : cn.getPackageName(); +    } + +    @Override +    public void startMonitoring() { +        final IntentFilter filter = new IntentFilter(ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL); +        mContext.registerReceiverAsUser(mSmsAppChangedWatcher, UserHandle.ALL, filter, +                /* permission= */ null, mHandler); +    } + +    private final BroadcastReceiver mSmsAppChangedWatcher = new BroadcastReceiver() { +        @Override +        public void onReceive(Context context, Intent intent) { +            if (ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL.equals(intent.getAction())) { +                mListener.accept(SmsAppServiceFinder.this, getSendingUserId()); +            } +        } +    }; +} diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8caa70283acf..f0ff570e385b 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -627,6 +627,13 @@ public class AudioService extends IAudioService.Stub      // If absolute volume is supported in AVRCP device      private boolean mAvrcpAbsVolSupported = false; +    // Pre-scale for Bluetooth Absolute Volume +    private float[] mPrescaleAbsoluteVolume = new float[] { +        0.5f,    // Pre-scale for index 1 +        0.7f,    // Pre-scale for index 2 +        0.85f,   // Pre-scale for index 3 +    }; +      private static Long mLastDeviceConnectMsgTime = new Long(0);      private NotificationManager mNm; @@ -878,6 +885,23 @@ public class AudioService extends IAudioService.Stub          mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);          mRecordMonitor.initMonitor(); + +        final float[] preScale = new float[3]; +        preScale[0] = mContext.getResources().getFraction( +                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1, +                1, 1); +        preScale[1] = mContext.getResources().getFraction( +                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2, +                1, 1); +        preScale[2] = mContext.getResources().getFraction( +                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3, +                1, 1); +        for (int i = 0; i < preScale.length; i++) { +            if (0.0f <= preScale[i] && preScale[i] <= 1.0f) { +                mPrescaleAbsoluteVolume[i] = preScale[i]; +            } +        } +      }      public void systemReady() { @@ -4661,7 +4685,9 @@ public class AudioService extends IAudioService.Stub      @Override      public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)      { -        Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState"); +        mDeviceLogger.log((new AudioEventLogger.StringEvent( +                "setHearingAidDeviceConnectionState state=" + state +                        + " addr=" + device.getAddress())).printLog(TAG));          setBluetoothHearingAidDeviceConnectionState(                  device, state,  false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE); @@ -4699,12 +4725,12 @@ public class AudioService extends IAudioService.Stub      public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,                  int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)      { -        mDeviceLogger.log(new AudioEventLogger.StringEvent( +        mDeviceLogger.log((new AudioEventLogger.StringEvent(                  "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state                  // only querying address as this is the only readily available field on the device                  + " addr=" + device.getAddress()                  + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent -                + " vol=" + a2dpVolume)); +                + " vol=" + a2dpVolume)).printLog(TAG));          if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {              mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored"));              return 0; @@ -4926,18 +4952,12 @@ public class AudioService extends IAudioService.Stub              if (index == 0) {                  // 0% for volume 0                  index = 0; -            } else if (index == 1) { -                // 50% for volume 1 -                index = (int)(mIndexMax * 0.5) /10; -            } else if (index == 2) { -                // 70% for volume 2 -                index = (int)(mIndexMax * 0.70) /10; -            } else if (index == 3) { -                // 85% for volume 3 -                index = (int)(mIndexMax * 0.85) /10; +            } else if (index > 0 && index <= 3) { +                // Pre-scale for volume steps 1 2 and 3 +                index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10;              } else {                  // otherwise, full gain -                index = (mIndexMax + 5)/10; +                index = (mIndexMax + 5) / 10;              }              return index;          } @@ -5870,6 +5890,8 @@ public class AudioService extends IAudioService.Stub      }      private void onSendBecomingNoisyIntent() { +        mDeviceLogger.log((new AudioEventLogger.StringEvent( +                "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));          sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));      } @@ -7235,7 +7257,7 @@ public class AudioService extends IAudioService.Stub      // - wired: logged before onSetWiredDeviceConnectionState() is executed      // - A2DP: logged at reception of method call      final private AudioEventLogger mDeviceLogger = new AudioEventLogger( -            LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection"); +            LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP/hearing aid device connection");      final private AudioEventLogger mForceUseLogger = new AudioEventLogger(              LOG_NB_EVENTS_FORCE_USE, diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 0f68c6889680..87cf9c434fc0 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -39,6 +39,7 @@ import android.os.Looper;  import android.os.RemoteException;  import android.os.ServiceManager;  import android.os.UserHandle; +import android.provider.Settings;  import android.util.Slog;  import com.android.internal.R; @@ -156,9 +157,18 @@ public class BiometricService extends SystemService {                      } else if (mCurrentModality == BIOMETRIC_IRIS) {                          Slog.w(TAG, "Unsupported modality");                      } else if (mCurrentModality == BIOMETRIC_FACE) { -                        mFaceService.authenticateFromService(true /* requireConfirmation */, token, -                                sessionId, userId, receiver, flags, opPackageName, bundle, -                                dialogReceiver, callingUid, callingPid, callingUserId); +                        // If the user disabled face for apps, return ERROR_HW_UNAVAILABLE +                        if (isFaceEnabledForApps()) { +                            receiver.onError(0 /* deviceId */, +                                    BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, +                                    FaceManager.getErrorString(getContext(), +                                            BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, +                                            0 /* vendorCode */)); +                        } else { +                            mFaceService.authenticateFromService(true /* requireConfirmation */, +                                    token, sessionId, userId, receiver, flags, opPackageName, +                                    bundle, dialogReceiver, callingUid, callingPid, callingUserId); +                        }                      } else {                          Slog.w(TAG, "Unsupported modality");                      } @@ -168,6 +178,15 @@ public class BiometricService extends SystemService {              });          } +        private boolean isFaceEnabledForApps() { +            // TODO: maybe cache this and eliminate duplicated code with KeyguardUpdateMonitor +            return Settings.Secure.getIntForUser( +                    getContext().getContentResolver(), +                    Settings.Secure.FACE_UNLOCK_APP_ENABLED, +                    1 /* default */, +                    UserHandle.USER_CURRENT) == 0; +        } +          @Override // Binder call          public void cancelAuthentication(IBinder token, String opPackageName)                  throws RemoteException { diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index 98c38dd41bfc..f6af52ae00a3 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -28,10 +28,11 @@ import android.content.pm.UserInfo;  import android.hardware.biometrics.BiometricAuthenticator;  import android.hardware.biometrics.BiometricConstants;  import android.hardware.biometrics.IBiometricPromptReceiver; -import android.hardware.biometrics.IBiometricServiceReceiver;  import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; +import android.hardware.biometrics.IBiometricServiceReceiver;  import android.hardware.biometrics.face.V1_0.IBiometricsFace;  import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; +import android.hardware.biometrics.face.V1_0.Status;  import android.hardware.face.Face;  import android.hardware.face.FaceManager;  import android.hardware.face.IFaceService; @@ -121,15 +122,15 @@ public class FaceService extends BiometricServiceBase {           * The following methods contain common code which is shared in biometrics/common.           */          @Override // Binder call -        public long preEnroll(IBinder token) { +        public long generateChallenge(IBinder token) {              checkPermission(MANAGE_BIOMETRIC); -            return startPreEnroll(token); +            return startGenerateChallenge(token);          }          @Override // Binder call -        public int postEnroll(IBinder token) { +        public int revokeChallenge(IBinder token) {              checkPermission(MANAGE_BIOMETRIC); -            return startPostEnroll(token); +            return startRevokeChallenge(token);          }          @Override // Binder call @@ -346,6 +347,45 @@ public class FaceService extends BiometricServiceBase {              // TODO: confirm security token when we move timeout management into the HAL layer.              mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);          } + +        @Override +        public int setRequireAttention(boolean requireAttention, final byte[] token) { +            checkPermission(MANAGE_BIOMETRIC); + +            final ArrayList<Byte> byteToken = new ArrayList<>(); +            for (int i = 0; i < token.length; i++) { +                byteToken.add(token[i]); +            } + +            int result; +            try { +                result = mDaemon != null ? mDaemon.setRequireAttention(requireAttention, byteToken) +                        : Status.INTERNAL_ERROR; +            } catch (RemoteException e) { +                Slog.e(getTag(), "Unable to setRequireAttention to " + requireAttention); +                result = Status.INTERNAL_ERROR; +            } + +            return result; +        } + +        @Override +        public boolean getRequireAttention(final byte[] token) { +            checkPermission(MANAGE_BIOMETRIC); + +            final ArrayList<Byte> byteToken = new ArrayList<>(); +            for (int i = 0; i < token.length; i++) { +                byteToken.add(token[i]); +            } + +            boolean result = true; +            try { +                result = mDaemon != null ? mDaemon.getRequireAttention(byteToken).value : true; +            } catch (RemoteException e) { +                Slog.e(getTag(), "Unable to getRequireAttention"); +            } +            return result; +        }      }      /** @@ -779,30 +819,30 @@ public class FaceService extends BiometricServiceBase {          return mDaemon;      } -    private long startPreEnroll(IBinder token) { +    private long startGenerateChallenge(IBinder token) {          IBiometricsFace daemon = getFaceDaemon();          if (daemon == null) { -            Slog.w(TAG, "startPreEnroll: no face HAL!"); +            Slog.w(TAG, "startGenerateChallenge: no face HAL!");              return 0;          }          try {              return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;          } catch (RemoteException e) { -            Slog.e(TAG, "startPreEnroll failed", e); +            Slog.e(TAG, "startGenerateChallenge failed", e);          }          return 0;      } -    private int startPostEnroll(IBinder token) { +    private int startRevokeChallenge(IBinder token) {          IBiometricsFace daemon = getFaceDaemon();          if (daemon == null) { -            Slog.w(TAG, "startPostEnroll: no face HAL!"); +            Slog.w(TAG, "startRevokeChallenge: no face HAL!");              return 0;          }          try {              return daemon.revokeChallenge();          } catch (RemoteException e) { -            Slog.e(TAG, "startPostEnroll failed", e); +            Slog.e(TAG, "startRevokeChallenge failed", e);          }          return 0;      } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 873a8e314bb1..a769590447ab 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -629,6 +629,11 @@ public class ClipboardService extends SystemService {          if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {              return false;          } +        // Shell can access the clipboard for testing purposes. +        if (mPm.checkPermission(android.Manifest.permission.READ_CLIPBOARD_IN_BACKGROUND, +                    callingPackage) == PackageManager.PERMISSION_GRANTED) { +            return true; +        }          // The default IME is always allowed to access the clipboard.          String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),                  Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.getUserId(callingUid)); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 2a80f0e7c291..48082b64ddfc 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -163,8 +163,8 @@ public class Vpn {      // TODO: create separate trackers for each unique VPN to support      // automated reconnection -    private Context mContext; -    private NetworkInfo mNetworkInfo; +    private final Context mContext; +    private final NetworkInfo mNetworkInfo;      private String mPackage;      private int mOwnerUID;      private String mInterface; diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index 2b1d9196fe18..1e6bb04858a1 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -320,9 +320,8 @@ public class TetheringConfiguration {      }      private static boolean getEnableLegacyDhcpServer(Context ctx) { -        // TODO: make the default false (0) and update javadoc in Settings.java          final ContentResolver cr = ctx.getContentResolver(); -        final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); +        final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);          return intVal != 0;      } diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index d8d650b28dee..5698fdf439a8 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -1226,7 +1226,7 @@ public final class ContentService extends IContentService.Stub {          if (userId == UserHandle.USER_ALL) {              mContext.enforceCallingOrSelfPermission( -                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); +                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);          } else if (userId < 0) {              throw new IllegalArgumentException("Invalid user: " + userId);          } else if (userId != UserHandle.getCallingUserId()) { @@ -1247,7 +1247,7 @@ public final class ContentService extends IContentService.Stub {                              ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +                                      Manifest.permission.INTERACT_ACROSS_USERS)                              : Manifest.permission.INTERACT_ACROSS_USERS_FULL; -                    throw new SecurityException(TAG + "Neither user " + uid +                    throw new SecurityException("No access to " + uri + ": neither user " + uid                              + " nor current process has " + permissions);                  }              } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index cade07cfb821..5005ea7e55f8 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4289,7 +4289,8 @@ public class NotificationManagerService extends SystemService {          }          // posted from app A on behalf of app A          if (isCallerSameApp(targetPkg, callingUid, userId) -                && TextUtils.equals(callingPkg, targetPkg)) { +                && (TextUtils.equals(callingPkg, targetPkg) +                || isCallerSameApp(callingPkg, callingUid, userId))) {              return callingUid;          } @@ -4306,7 +4307,8 @@ public class NotificationManagerService extends SystemService {              return targetUid;          } -        throw new SecurityException("Caller " + callingUid + " cannot post for pkg " + targetPkg); +        throw new SecurityException("Caller " + callingPkg + ":" + callingUid +                + " cannot post for pkg " + targetPkg + " in user " + userId);      }      /** @@ -4326,7 +4328,7 @@ public class NotificationManagerService extends SystemService {          if (!isSystemNotification && !isNotificationFromListener) {              synchronized (mNotificationLock) {                  if (mNotificationsByKey.get(r.sbn.getKey()) == null -                        && isCallerInstantApp(pkg, callingUid, r.getUserId())) { +                        && isCallerInstantApp(pkg, Binder.getCallingUid(), userId)) {                      // Ephemeral apps have some special constraints for notifications.                      // They are not allowed to create new notifications however they are allowed to                      // update notifications created by the system (e.g. a foreground service @@ -4732,7 +4734,8 @@ public class NotificationManagerService extends SystemService {                      if (notification.getSmallIcon() != null) {                          StatusBarNotification oldSbn = (old != null) ? old.sbn : null;                          mListeners.notifyPostedLocked(r, old); -                        if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) { +                        if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) +                                && !isCritical(r)) {                              mHandler.post(new Runnable() {                                  @Override                                  public void run() { @@ -4902,6 +4905,19 @@ public class NotificationManagerService extends SystemService {      }      /** +     * Check if the notification is classified as critical. +     * +     * @param record the record to test for criticality +     * @return {@code true} if notification is considered critical +     * +     * @see CriticalNotificationExtractor for criteria +     */ +    private boolean isCritical(NotificationRecord record) { +        // 0 is the most critical +        return record.getCriticality() < CriticalNotificationExtractor.NORMAL; +    } + +    /**       * Keeps the last 5 packages that have notified, by user.       */      @GuardedBy("mNotificationLock") diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 8f2833f68192..006ea75ea160 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;  import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;  import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;  import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; +import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;  import static android.content.pm.PackageParser.APK_FILE_EXTENSION;  import static android.system.OsConstants.O_CREAT;  import static android.system.OsConstants.O_RDONLY; @@ -1060,6 +1061,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {      @GuardedBy("mLock")      private void validateInstallLocked(@Nullable PackageInfo pkgInfo)              throws PackageManagerException { +        ApkLite baseApk = null;          mPackageName = null;          mVersionCode = -1;          mSigningDetails = PackageParser.SigningDetails.UNKNOWN; @@ -1136,6 +1138,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {              // Base is coming from session              if (apk.splitName == null) {                  mResolvedBaseFile = targetFile; +                baseApk = apk;              }              mResolvedStagedFiles.add(targetFile); @@ -1221,6 +1224,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {                  if (baseDexMetadataFile != null) {                      mResolvedInheritedFiles.add(baseDexMetadataFile);                  } +                baseApk = existingBase;              }              // Inherit splits if not overridden @@ -1300,6 +1304,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {                  }              }          } +        if (baseApk.isSplitRequired && stagedSplits.size() <= 1) { +            throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, +                    "Missing split for " + mPackageName); +        }      }      @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e10827bc6101..329b1da82608 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8474,7 +8474,7 @@ public class PackageManagerService extends IPackageManager.Stub      private boolean canSkipFullApkVerification(String apkPath) {          final byte[] rootHashObserved;          try { -            rootHashObserved = VerityUtils.generateFsverityRootHash(apkPath); +            rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);              if (rootHashObserved == null) {                  return false;  // APK does not contain Merkle tree root hash.              } @@ -16004,12 +16004,14 @@ public class PackageManagerService extends IPackageManager.Stub              }              if (apkPath != null) {                  final VerityUtils.SetupResult result = -                        VerityUtils.generateApkVeritySetupData(apkPath); +                        VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */, +                                true /* skipSigningBlock */);                  if (result.isOk()) {                      if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);                      FileDescriptor fd = result.getUnownedFileDescriptor();                      try { -                        final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath); +                        final byte[] signedRootHash = +                                VerityUtils.generateApkVerityRootHash(apkPath);                          mInstaller.installApkVerity(apkPath, fd, result.getContentSize());                          mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);                      } catch (InstallerException | IOException | DigestException | @@ -23097,7 +23099,9 @@ public class PackageManagerService extends IPackageManager.Stub                  return false;              }          } -        if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)) { +        if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId) +                  || sUserManager.hasUserRestriction( +                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) {              return false;          }          if (mExternalSourcesPolicy != null) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index a9f1b5c05a7f..93729d1949b0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -124,6 +124,7 @@ class PackageManagerShellCommand extends ShellCommand {      int mTargetUser;      boolean mBrief;      boolean mComponents; +    int mQueryFlags;      PackageManagerShellCommand(PackageManagerService service) {          mInterface = service; @@ -739,6 +740,9 @@ class PackageManagerShellCommand extends ShellCommand {                  } else if ("--components".equals(opt)) {                      mComponents = true;                      return true; +                } else if ("--query-flags".equals(opt)) { +                    mQueryFlags = Integer.decode(cmd.getNextArgRequired()); +                    return true;                  }                  return false;              } @@ -784,7 +788,8 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            ResolveInfo ri = mInterface.resolveIntent(intent, intent.getType(), 0, mTargetUser); +            ResolveInfo ri = mInterface.resolveIntent(intent, intent.getType(), mQueryFlags, +                    mTargetUser);              PrintWriter pw = getOutPrintWriter();              if (ri == null) {                  pw.println("No activity found"); @@ -806,8 +811,8 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, intent.getType(), 0, -                    mTargetUser).getList(); +            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, intent.getType(), +                    mQueryFlags, mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) {                  pw.println("No activities found"); @@ -840,8 +845,8 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentServices(intent, intent.getType(), 0, -                    mTargetUser).getList(); +            List<ResolveInfo> result = mInterface.queryIntentServices(intent, intent.getType(), +                    mQueryFlags, mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) {                  pw.println("No services found"); @@ -874,8 +879,8 @@ class PackageManagerShellCommand extends ShellCommand {              throw new RuntimeException(e.getMessage(), e);          }          try { -            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, intent.getType(), 0, -                    mTargetUser).getList(); +            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, intent.getType(), +                    mQueryFlags, mTargetUser).getList();              PrintWriter pw = getOutPrintWriter();              if (result == null || result.size() <= 0) {                  pw.println("No receivers found"); @@ -2731,16 +2736,20 @@ class PackageManagerShellCommand extends ShellCommand {          pw.println("      -d: only list dangerous permissions");          pw.println("      -u: list only the permissions users will see");          pw.println(""); -        pw.println("  resolve-activity [--brief] [--components] [--user USER_ID] INTENT"); +        pw.println("  resolve-activity [--brief] [--components] [--query-flags FLAGS]"); +        pw.println("       [--user USER_ID] INTENT");          pw.println("    Prints the activity that resolves to the given INTENT.");          pw.println(""); -        pw.println("  query-activities [--brief] [--components] [--user USER_ID] INTENT"); +        pw.println("  query-activities [--brief] [--components] [--query-flags FLAGS]"); +        pw.println("       [--user USER_ID] INTENT");          pw.println("    Prints all activities that can handle the given INTENT.");          pw.println(""); -        pw.println("  query-services [--brief] [--components] [--user USER_ID] INTENT"); +        pw.println("  query-services [--brief] [--components] [--query-flags FLAGS]"); +        pw.println("       [--user USER_ID] INTENT");          pw.println("    Prints all services that can handle the given INTENT.");          pw.println(""); -        pw.println("  query-receivers [--brief] [--components] [--user USER_ID] INTENT"); +        pw.println("  query-receivers [--brief] [--components] [--query-flags FLAGS]"); +        pw.println("       [--user USER_ID] INTENT");          pw.println("    Prints all broadcast receivers that can handle the given INTENT.");          pw.println("");          pw.println("  install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]"); diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 3f28ee659a58..13155027a387 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -16,10 +16,6 @@  package com.android.server.pm; -import com.google.android.collect.Sets; - -import com.android.internal.util.Preconditions; -  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityManager; @@ -42,6 +38,10 @@ import android.util.Log;  import android.util.Slog;  import android.util.SparseArray; +import com.android.internal.util.Preconditions; + +import com.google.android.collect.Sets; +  import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlSerializer; @@ -77,6 +77,7 @@ public class UserRestrictionsUtils {              UserManager.DISALLOW_UNINSTALL_APPS,              UserManager.DISALLOW_SHARE_LOCATION,              UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, +            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,              UserManager.DISALLOW_CONFIG_BLUETOOTH,              UserManager.DISALLOW_BLUETOOTH,              UserManager.DISALLOW_BLUETOOTH_SHARING, @@ -211,7 +212,8 @@ public class UserRestrictionsUtils {       */      private static final Set<String> PROFILE_GLOBAL_RESTRICTIONS = Sets.newArraySet(              UserManager.ENSURE_VERIFY_APPS, -            UserManager.DISALLOW_AIRPLANE_MODE +            UserManager.DISALLOW_AIRPLANE_MODE, +            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY      );      /** @@ -517,13 +519,18 @@ public class UserRestrictionsUtils {                                  userId);                      }                      break; +                case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY: +                    setInstallMarketAppsRestriction(cr, userId, getNewUserRestrictionSetting( +                            context, userId, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, +                            newValue)); +                    break;                  case UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES:                      // Since Android O, the secure setting is not available to be changed by the                      // user. Hence, when the restriction is cleared, we need to reset the state of                      // the setting to its default value which is now 1. -                    android.provider.Settings.Secure.putIntForUser(cr, -                            android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, -                            newValue ? 0 : 1, userId); +                    setInstallMarketAppsRestriction(cr, userId, getNewUserRestrictionSetting( +                            context, userId, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, +                            newValue));                      break;                  case UserManager.DISALLOW_RUN_IN_BACKGROUND:                      if (newValue) { @@ -813,4 +820,16 @@ public class UserRestrictionsUtils {          }          return false;      } + +    private static void setInstallMarketAppsRestriction(ContentResolver cr, int userId, +            int settingValue) { +        android.provider.Settings.Secure.putIntForUser( +                cr, android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, settingValue, userId); +    } + +    private static int getNewUserRestrictionSetting(Context context, int userId, +                String userRestriction, boolean newValue) { +        return (newValue || UserManager.get(context).hasUserRestriction(userRestriction, +                UserHandle.of(userId))) ? 0 : 1; +    }  } diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING new file mode 100644 index 000000000000..ad5255904d20 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING @@ -0,0 +1,22 @@ +{ +  "presubmit": [ +    { +      "name": "DexLoggerTests" +    }, +    { +      "name": "DexManagerTests" +    }, +    { +      "name": "DexoptOptionsTests" +    }, +    { +      "name": "DexoptUtilsTest" +    }, +    { +      "name": "PackageDexUsageTests" +    }, +    { +      "name": "DexLoggerIntegrationTests" +    } +  ] +} diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java index 5e66bfc3cd3e..82d6b226df9f 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionsState.java +++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java @@ -135,7 +135,8 @@ public final class PermissionsState {              final int userCount = other.mPermissionReviewRequired.size();              for (int i = 0; i < userCount; i++) {                  final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i); -                mPermissionReviewRequired.put(i, reviewRequired); +                mPermissionReviewRequired.put(other.mPermissionReviewRequired.keyAt(i), +                        reviewRequired);              }          }      } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index deeae26d034c..2557f46ba34b 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2828,7 +2828,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {                  // Assumes it's safe to show starting windows of launched apps while                  // the keyguard is being hidden. This is okay because starting windows never show                  // secret information. -                if (mKeyguardOccluded) { +                // TODO(b/113840485): Occluded may not only happen on default display +                if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {                      windowFlags |= FLAG_SHOW_WHEN_LOCKED;                  }              } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 68e636a2afc2..5adc248cee79 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -190,6 +190,8 @@ public class Notifier {          try {              mBatteryStats.noteInteractive(true);          } catch (RemoteException ex) { } +        StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED, +                StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON);      }      /** @@ -401,6 +403,9 @@ public class Notifier {              try {                  mBatteryStats.noteInteractive(interactive);              } catch (RemoteException ex) { } +            StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED, +                    interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON : +                            StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);              // Handle early behaviors.              mInteractive = interactive; diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java index 9f69702911c9..8070f3add5c6 100644 --- a/services/core/java/com/android/server/security/VerityUtils.java +++ b/services/core/java/com/android/server/security/VerityUtils.java @@ -28,40 +28,74 @@ import android.util.Slog;  import android.util.apk.ApkSignatureVerifier;  import android.util.apk.ByteBufferFactory;  import android.util.apk.SignatureNotFoundException; +import android.util.apk.VerityBuilder; + +import libcore.util.HexEncoding;  import java.io.FileDescriptor;  import java.io.IOException; +import java.io.RandomAccessFile;  import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths;  import java.security.DigestException; +import java.security.MessageDigest;  import java.security.NoSuchAlgorithmException;  import java.util.Arrays; +import sun.security.pkcs.PKCS7; +  /** Provides fsverity related operations. */  abstract public class VerityUtils {      private static final String TAG = "VerityUtils"; +    /** The maximum size of signature file.  This is just to avoid potential abuse. */ +    private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; +      private static final boolean DEBUG = false;      /** -     * Generates Merkle tree and fsverity metadata. +     * Generates Merkle tree and fs-verity metadata.       * -     * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the +     * @return {@code SetupResult} that contains the result code, and when success, the       *         {@code FileDescriptor} to read all the data from.       */ -    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { -        if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath); +    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath, +            String signaturePath, boolean skipSigningBlock) { +        if (DEBUG) { +            Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " +                    + signaturePath); +        }          SharedMemory shm = null;          try { -            byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath); -            if (signedRootHash == null) { +            byte[] signedVerityHash; +            if (skipSigningBlock) { +                signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath); +            } else { +                Path path = Paths.get(signaturePath); +                if (Files.exists(path)) { +                    // TODO(112037636): fail early if the signing key is not in .fs-verity keyring. +                    PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path)); +                    signedVerityHash = pkcs7.getContentInfo().getContentBytes(); +                    if (DEBUG) { +                        Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash)); +                    } +                } else { +                    signedVerityHash = null; +                } +            } + +            if (signedVerityHash == null) {                  if (DEBUG) { -                    Slog.d(TAG, "Skip verity tree generation since there is no root hash"); +                    Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");                  }                  return SetupResult.skipped();              } -            Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath, -                    signedRootHash); +            Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, +                    signaturePath, signedVerityHash, skipSigningBlock);              shm = result.first;              int contentSize = result.second;              FileDescriptor rfd = shm.getFileDescriptor(); @@ -81,9 +115,9 @@ abstract public class VerityUtils {      }      /** -     * {@see ApkSignatureVerifier#generateFsverityRootHash(String)}. +     * {@see ApkSignatureVerifier#generateApkVerityRootHash(String)}.       */ -    public static byte[] generateFsverityRootHash(@NonNull String apkPath) +    public static byte[] generateApkVerityRootHash(@NonNull String apkPath)              throws NoSuchAlgorithmException, DigestException, IOException {          return ApkSignatureVerifier.generateApkVerityRootHash(apkPath);      } @@ -97,22 +131,114 @@ abstract public class VerityUtils {      }      /** +     * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code +     * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and +     * extensions, including a PKCS#7 signature provided in {@code signaturePath}. +     * +     * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code +     * ByteBuffer}. The data will be used outside this method via the factory itself. +     * +     * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor +     *         and authenticated extensions. +     */ +    private static byte[] generateFsverityMetadata(String filePath, String signaturePath, +            @NonNull TrackedShmBufferFactory trackedBufferFactory) +            throws IOException, SignatureNotFoundException, SecurityException, DigestException, +                   NoSuchAlgorithmException { +        try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { +            VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree( +                    file, trackedBufferFactory); + +            ByteBuffer buffer = result.verityData; +            buffer.position(result.merkleTreeSize); +            return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, +                    buffer); +        } +    } + +    /** +     * Generates fs-verity descriptor including the extensions to the {@code output} and returns the +     * fs-verity measurement. +     * +     * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated +     *         extensions. +     */ +    private static byte[] generateFsverityDescriptorAndMeasurement( +            @NonNull RandomAccessFile file, @NonNull byte[] rootHash, +            @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output) +            throws IOException, NoSuchAlgorithmException, DigestException { +        final short kRootHashExtensionId = 1; +        final short kPkcs7SignatureExtensionId = 3; +        final int origPosition = output.position(); + +        // For generating fs-verity file measurement, which consists of the descriptor and +        // authenticated extensions (but not unauthenticated extensions and the footer). +        MessageDigest md = MessageDigest.getInstance("SHA-256"); + +        // 1. Generate fs-verity descriptor. +        final byte[] desc = constructFsverityDescriptorNative(file.length()); +        output.put(desc); +        md.update(desc); + +        // 2. Generate authenticated extensions. +        final byte[] authExt = +                constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length); +        output.put(authExt); +        output.put(rootHash); +        md.update(authExt); +        md.update(rootHash); + +        // 3. Generate unauthenticated extensions. +        ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); +        output.putShort((short) 1);  // number of unauthenticated extensions below +        output.position(output.position() + 6); + +        // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be +        // done by the caller if needed). +        Path path = Paths.get(pkcs7SignaturePath); +        if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) { +            throw new IllegalArgumentException("Signature size is unexpectedly large: " +                    + pkcs7SignaturePath); +        } +        final byte[] pkcs7Signature = Files.readAllBytes(path); +        output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId, +                    pkcs7Signature.length)); +        output.put(pkcs7Signature); + +        // 4. Generate the footer. +        output.put(constructFsverityFooterNative(output.position() - origPosition)); + +        return md.digest(); +    } + +    private static native byte[] constructFsverityDescriptorNative(long fileSize); +    private static native byte[] constructFsverityExtensionNative(short extensionId, +            int extensionDataSize); +    private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead); + +    /**       * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains       * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used       * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has       * length equals to the returned {@code Integer}.       */ -    private static Pair<SharedMemory, Integer> generateApkVerityIntoSharedMemory( -            String apkPath, byte[] expectedRootHash) +    private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory( +            String apkPath, String signaturePath, @NonNull byte[] expectedRootHash, +            boolean skipSigningBlock)              throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,                     SignatureNotFoundException {          TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); -        byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, -                shmBufferFactory); +        byte[] generatedRootHash; +        if (skipSigningBlock) { +            generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); +        } else { +            generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory); +        }          // We only generate Merkle tree once here, so it's important to make sure the root hash          // matches the signed one in the apk.          if (!Arrays.equals(expectedRootHash, generatedRootHash)) { -            throw new SecurityException("Locally generated verity root hash does not match"); +            throw new SecurityException("verity hash mismatch: " +                    + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash));          }          int contentSize = shmBufferFactory.getBufferLimit(); @@ -126,11 +252,15 @@ abstract public class VerityUtils {          return Pair.create(shm, contentSize);      } +    private static String bytesToString(byte[] bytes) { +        return HexEncoding.encodeToString(bytes); +    } +      public static class SetupResult {          /** Result code if verity is set up correctly. */          private static final int RESULT_OK = 1; -        /** Result code if the apk does not contain a verity root hash. */ +        /** Result code if signature is not provided. */          private static final int RESULT_SKIPPED = 2;          /** Result code if the setup failed. */ diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index bfa03ca9f2be..d0de9409c49e 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -47,6 +47,7 @@ import android.os.IStatsManager;  import android.os.IStoraged;  import android.os.IThermalEventListener;  import android.os.IThermalService; +import android.os.ParcelFileDescriptor;  import android.os.Parcelable;  import android.os.Process;  import android.os.RemoteException; @@ -63,10 +64,13 @@ import android.os.storage.StorageManager;  import android.telephony.ModemActivityInfo;  import android.telephony.TelephonyManager;  import android.util.ArrayMap; +import android.util.Log;  import android.util.Slog;  import android.util.StatsLog;  import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.procstats.IProcessStats; +import com.android.internal.app.procstats.ProcessStats;  import com.android.internal.net.NetworkStatsFactory;  import com.android.internal.os.BinderCallsStats.ExportedCallStat;  import com.android.internal.os.KernelCpuSpeedReader; @@ -78,10 +82,12 @@ import com.android.internal.os.KernelWakelockReader;  import com.android.internal.os.KernelWakelockStats;  import com.android.internal.os.LooperStats;  import com.android.internal.os.PowerProfile; +import com.android.internal.os.StoragedUidIoStatsReader;  import com.android.internal.util.DumpUtils;  import com.android.server.BinderCallsStatsService;  import com.android.server.LocalServices;  import com.android.server.SystemService; +import com.android.server.SystemServiceManager;  import com.android.server.storage.DiskStatsFileLogger;  import com.android.server.storage.DiskStatsLoggingService; @@ -95,6 +101,7 @@ import java.io.File;  import java.io.FileDescriptor;  import java.io.FileOutputStream;  import java.io.IOException; +import java.io.InputStream;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.Arrays; @@ -123,7 +130,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {      public static final String CONFIG_DIR = "/data/misc/stats-service";      static final String TAG = "StatsCompanionService"; -    static final boolean DEBUG = true; +    static final boolean DEBUG = false;      public static final int CODE_DATA_BROADCAST = 1;      public static final int CODE_SUBSCRIBER_BROADCAST = 1; @@ -172,14 +179,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {              new KernelUidCpuActiveTimeReader();      private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =              new KernelUidCpuClusterTimeReader(); +    private StoragedUidIoStatsReader mStoragedUidIoStatsReader = +            new StoragedUidIoStatsReader();      private static IThermalService sThermalService; +    private File mBaseDir = +            new File(SystemServiceManager.ensureSystemDir(), "stats_companion");      public StatsCompanionService(Context context) {          super();          mContext = context;          mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - +        mBaseDir.mkdirs();          mAppUpdateReceiver = new AppUpdateReceiver();          mUserUpdateReceiver = new BroadcastReceiver() {              @Override @@ -966,6 +977,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {              e.writeLong(processMemoryState.rssInBytes);              e.writeLong(processMemoryState.cacheInBytes);              e.writeLong(processMemoryState.swapInBytes); +            e.writeLong(processMemoryState.rssHighWatermarkInBytes);              pulledData.add(e);          }      } @@ -1244,6 +1256,107 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {          Binder.restoreCallingIdentity(token);      } +    long mLastProcStatsHighWaterMark = readProcStatsHighWaterMark(); + +    private long readProcStatsHighWaterMark() { +        try { +            File[] files = mBaseDir.listFiles(); +            if (files == null || files.length == 0) { +                return 0; +            } +            if (files.length > 1) { +                Log.e(TAG, "Only 1 file expected for high water mark. Found " + files.length); +            } +            return Long.valueOf(files[0].getName()); +        } catch (SecurityException e) { +            Log.e(TAG, "Failed to get procstats high watermark file.", e); +        } catch (NumberFormatException e) { +            Log.e(TAG, "Failed to parse file name.", e); +        } +        return 0; +    } + +    private IProcessStats mProcessStats = +            IProcessStats.Stub.asInterface(ServiceManager.getService(ProcessStats.SERVICE_NAME)); + +    private void pullProcessStats( +            int tagId, long elapsedNanos, long wallClockNanos, +            List<StatsLogEventWrapper> pulledData) { +        try { +            List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); +            long highWaterMark = mProcessStats.getCommittedStats( +                    mLastProcStatsHighWaterMark, ProcessStats.REPORT_ALL, true, statsFiles); +            if (statsFiles.size() != 1) { +                return; +            } +            InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0)); +            int[] len = new int[1]; +            byte[] stats = readFully(stream, len); +            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); +            e.writeStorage(Arrays.copyOf(stats, len[0])); +            pulledData.add(e); +            new File(mBaseDir.getAbsolutePath() + "/" + mLastProcStatsHighWaterMark).delete(); +            mLastProcStatsHighWaterMark = highWaterMark; +            new File( +                    mBaseDir.getAbsolutePath() + "/" + mLastProcStatsHighWaterMark).createNewFile(); +        } catch (IOException e) { +            Log.e(TAG, "Getting procstats failed: ", e); +        } catch (RemoteException e) { +            Log.e(TAG, "Getting procstats failed: ", e); +        } catch (SecurityException e) { +            Log.e(TAG, "Getting procstats failed: ", e); +        } +    } + +    static byte[] readFully(InputStream stream, int[] outLen) throws IOException { +        int pos = 0; +        final int initialAvail = stream.available(); +        byte[] data = new byte[initialAvail > 0 ? (initialAvail + 1) : 16384]; +        while (true) { +            int amt = stream.read(data, pos, data.length - pos); +            if (DEBUG) { +                Slog.i(TAG, "Read " + amt + " bytes at " + pos + " of avail " + data.length); +            } +            if (amt < 0) { +                if (DEBUG) { +                    Slog.i(TAG, "**** FINISHED READING: pos=" + pos + " len=" + data.length); +                } +                outLen[0] = pos; +                return data; +            } +            pos += amt; +            if (pos >= data.length) { +                byte[] newData = new byte[pos + 16384]; +                if (DEBUG) { +                    Slog.i(TAG, "Copying " + pos + " bytes to new array len " + newData.length); +                } +                System.arraycopy(data, 0, newData, 0, pos); +                data = newData; +            } +        } +    } + +    private void pullDiskIo(int tagId, long elapsedNanos, final long wallClockNanos, +            List<StatsLogEventWrapper> pulledData) { +        mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead, +                fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite, +                fgFsync, bgFsync) -> { +            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); +            e.writeInt(uid); +            e.writeLong(fgCharsRead); +            e.writeLong(fgCharsWrite); +            e.writeLong(fgBytesRead); +            e.writeLong(fgBytesWrite); +            e.writeLong(bgCharsRead); +            e.writeLong(bgCharsWrite); +            e.writeLong(bgBytesRead); +            e.writeLong(bgBytesWrite); +            e.writeLong(fgFsync); +            e.writeLong(bgFsync); +            pulledData.add(e); +        }); +    } +      /**       * Pulls various data.       */ @@ -1357,6 +1470,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {                  pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret);                  break;              } +            case StatsLog.PROC_STATS: { +                pullProcessStats(tagId, elapsedNanos, wallClockNanos, ret); +                break; +            } +            case StatsLog.DISK_IO: { +                pullDiskIo(tagId, elapsedNanos, wallClockNanos, ret); +                break; +            }              default:                  Slog.w(TAG, "No such tagId data as " + tagId);                  return null; @@ -1367,13 +1488,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {      @Override // Binder call      public void statsdReady() {          enforceCallingPermission(); -        if (DEBUG) Slog.d(TAG, "learned that statsdReady"); +        if (DEBUG) { +            Slog.d(TAG, "learned that statsdReady"); +        }          sayHiToStatsd(); // tell statsd that we're ready too and link to it -        mContext.sendBroadcastAsUser( -                new Intent(StatsManager.ACTION_STATSD_STARTED) +        mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)                          .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND), -                UserHandle.SYSTEM, -                android.Manifest.permission.DUMP); +                UserHandle.SYSTEM, android.Manifest.permission.DUMP);      }      @Override diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d2fc15a28c5..bcf9212464db 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -22,6 +22,7 @@ import android.app.AppProtoEnums;  import android.app.IActivityManager;  import android.app.IApplicationThread;  import android.content.ComponentName; +import android.content.IIntentSender;  import android.content.Intent;  import android.content.pm.ApplicationInfo;  import android.content.res.CompatibilityInfo; @@ -32,8 +33,12 @@ import android.service.voice.IVoiceInteractionSession;  import android.util.SparseIntArray;  import com.android.internal.app.IVoiceInteractor; +import com.android.server.am.PendingIntentRecord; +import com.android.server.am.SafeActivityOptions; +import com.android.server.am.TaskRecord;  import com.android.server.am.WindowProcessController; +import java.lang.ref.WeakReference;  import java.util.List;  /** @@ -178,6 +183,27 @@ public abstract class ActivityTaskManagerInternal {              int userId, Intent[] intents, Bundle bOptions);      /** +     * Start intents as a package. +     * +     * @param uid Make a call as if this UID did. +     * @param callingPackage Make a call as if this package did. +     * @param intents Intents to start. +     * @param userId Start the intents on this user. +     * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID. +     * @param originatingPendingIntent PendingIntentRecord that originated this activity start or +     *        null if not originated by PendingIntent +     */ +    public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, +            String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, +            boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent); + +    public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, +            String callingPackage, Intent intent, String resolvedType, IBinder resultTo, +            String resultWho, int requestCode, int startFlags, SafeActivityOptions options, +            int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, +            PendingIntentRecord originatingPendingIntent); + +    /**       * Start activity {@code intent} without calling user-id check.       *       * - DO NOT call it with the calling UID cleared. @@ -297,4 +323,13 @@ public abstract class ActivityTaskManagerInternal {       * @param displayId The ID of the display showing the IME.       */      public abstract void onImeWindowSetOnDisplay(int pid, int displayId); + +    public abstract void sendActivityResult(int callingUid, IBinder activityToken, +            String resultWho, int requestCode, int resultCode, Intent data); +    public abstract void clearPendingResultForActivity( +            IBinder activityToken, WeakReference<PendingIntentRecord> pir); +    public abstract IIntentSender getIntentSender(int type, String packageName, +            int callingUid, int userId, IBinder token, String resultWho, +            int requestCode, Intent[] intents, String[] resolvedTypes, int flags, +            Bundle bOptions);  } diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 00e30507d232..be8a0bd7ad32 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -35,12 +35,6 @@ interface AnimationAdapter {      long STATUS_BAR_TRANSITION_DURATION = 120L;      /** -     * @return Whether we should detach the wallpaper during the animation. -     * @see Animation#setDetachWallpaper -     */ -    boolean getDetachWallpaper(); - -    /**       * @return Whether we should show the wallpaper during the animation.       * @see Animation#getShowWallpaper()       */ diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 6da9f104a212..fc7610239fa3 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1632,17 +1632,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree          return null;      } -    int getLowestAnimLayer() { -        for (int i = 0; i < mChildren.size(); i++) { -            final WindowState w = mChildren.get(i); -            if (w.mRemoved) { -                continue; -            } -            return w.mWinAnimator.mAnimLayer; -        } -        return Integer.MAX_VALUE; -    } -      WindowState getHighestAnimLayerWindow(WindowState currentTarget) {          WindowState candidate = null;          for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) { @@ -1650,8 +1639,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree              if (w.mRemoved) {                  continue;              } -            if (candidate == null || w.mWinAnimator.mAnimLayer > -                    candidate.mWinAnimator.mAnimLayer) { +            if (candidate == null) {                  candidate = w;              }          } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index eaaf804d2cf9..a762fe9362c5 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -439,36 +439,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo              return;          } -        final int flags = w.mAttrs.flags; - -        // If this window is animating, make a note that we have an animating window and take -        // care of a request to run a detached wallpaper animation. -        if (winAnimator.isAnimationSet()) { -            final AnimationAdapter anim = w.getAnimation(); -            if (anim != null) { -                if ((flags & FLAG_SHOW_WALLPAPER) != 0 && anim.getDetachWallpaper()) { -                    mTmpWindow = w; -                } -                final int color = anim.getBackgroundColor(); -                if (color != 0) { -                    final TaskStack stack = w.getStack(); -                    if (stack != null) { -                        stack.setAnimationBackground(winAnimator, color); -                    } -                } -            } -        } - -        // If this window's app token is running a detached wallpaper animation, make a note so -        // we can ensure the wallpaper is displayed behind it. -        final AppWindowToken atoken = winAnimator.mWin.mAppToken; -        final AnimationAdapter animation = atoken != null ? atoken.getAnimation() : null; -        if (animation != null) { -            if ((flags & FLAG_SHOW_WALLPAPER) != 0 && animation.getDetachWallpaper()) { -                mTmpWindow = w; -            } - -            final int color = animation.getBackgroundColor(); +        // If this window is animating, ensure the animation background is set. +        final AnimationAdapter anim = w.mAppToken != null +                ? w.mAppToken.getAnimation() +                : w.getAnimation(); +        if (anim != null) { +            final int color = anim.getBackgroundColor();              if (color != 0) {                  final TaskStack stack = w.getStack();                  if (stack != null) { @@ -2307,21 +2283,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo          mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);      } -    /** -     * If a window that has an animation specifying a colored background and the current wallpaper -     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to -     * suddenly disappear. -     */ -    int getLayerForAnimationBackground(WindowStateAnimator winAnimator) { -        final WindowState visibleWallpaper = mBelowAppWindowsContainers.getWindow( -                w -> w.mIsWallpaper && w.isVisibleNow()); - -        if (visibleWallpaper != null) { -            return visibleWallpaper.mWinAnimator.mAnimLayer; -        } -        return winAnimator.mAnimLayer; -    } -      void prepareFreezingTaskBounds() {          for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {              final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); @@ -2652,6 +2613,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo       */      void setInputMethodWindowLocked(WindowState win) {          mInputMethodWindow = win; +        // Update display configuration for IME process. +        if (mInputMethodWindow != null) { +            final int imePid = mInputMethodWindow.mSession.mPid; +            mService.mAtmInternal.onImeWindowSetOnDisplay(imePid, +                    mInputMethodWindow.getDisplayId()); +        }          computeImeTarget(true /* updateImeTarget */);      } @@ -2740,22 +2707,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo                  if (highestTarget != null) {                      final AppTransition appTransition = mService.mAppTransition;                      if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget -                            + " animating=" + highestTarget.mWinAnimator.isAnimationSet() -                            + " layer=" + highestTarget.mWinAnimator.mAnimLayer -                            + " new layer=" + target.mWinAnimator.mAnimLayer); +                            + " animating=" + highestTarget.isAnimating());                      if (appTransition.isTransitionSet()) {                          // If we are currently setting up for an animation, hold everything until we                          // can find out what will happen.                          setInputMethodTarget(highestTarget, true);                          return highestTarget; -                    } else if (highestTarget.mWinAnimator.isAnimationSet() && -                            highestTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer) { -                        // If the window we are currently targeting is involved with an animation, -                        // and it is on top of the next target we will be over, then hold off on -                        // moving until that is done. -                        setInputMethodTarget(highestTarget, true); -                        return highestTarget;                      }                  }              } @@ -2928,26 +2886,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo          return false;      } -    void updateWindowsForAnimator(WindowAnimator animator) { -        mTmpWindowAnimator = animator; +    void updateWindowsForAnimator() {          forAllWindows(mUpdateWindowsForAnimator, true /* traverseTopToBottom */);      } -    void updateWallpaperForAnimator(WindowAnimator animator) { +    /** +     * Updates the {@link TaskStack#setAnimationBackground} for all windows. +     */ +    void updateBackgroundForAnimator() {          resetAnimationBackgroundAnimator(); - -        // Used to indicate a detached wallpaper. -        mTmpWindow = null; -        mTmpWindowAnimator = animator; -          forAllWindows(mUpdateWallpaperForAnimator, true /* traverseTopToBottom */); - -        if (animator.mWindowDetachedWallpaper != mTmpWindow) { -            if (DEBUG_WALLPAPER) Slog.v(TAG, "Detached wallpaper changed from " -                    + animator.mWindowDetachedWallpaper + " to " + mTmpWindow); -            animator.mWindowDetachedWallpaper = mTmpWindow; -            animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; -        }      }      boolean isInputMethodClientFocus(int uid, int pid) { diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java index d89d6f056218..77a024cc2e99 100644 --- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java @@ -44,11 +44,6 @@ class LocalAnimationAdapter implements AnimationAdapter {      }      @Override -    public boolean getDetachWallpaper() { -        return mSpec.getDetachWallpaper(); -    } - -    @Override      public boolean getShowWallpaper() {          return mSpec.getShowWallpaper();      } @@ -98,13 +93,6 @@ class LocalAnimationAdapter implements AnimationAdapter {      interface AnimationSpec {          /** -         * @see AnimationAdapter#getDetachWallpaper -         */ -        default boolean getDetachWallpaper() { -            return false; -        } - -        /**           * @see AnimationAdapter#getShowWallpaper           */          default boolean getShowWallpaper() { diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 1eae56745a75..6fef16304d42 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -20,8 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;  import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;  import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;  import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING;  import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; -  import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;  import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;  import static com.android.server.wm.AnimationAdapterProto.REMOTE; @@ -48,16 +48,13 @@ import android.view.IRecentsAnimationRunner;  import android.view.RemoteAnimationTarget;  import android.view.SurfaceControl;  import android.view.SurfaceControl.Transaction; -  import com.android.internal.annotations.VisibleForTesting;  import com.android.server.LocalServices;  import com.android.server.input.InputWindowHandle;  import com.android.server.inputmethod.InputMethodManagerInternal;  import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;  import com.android.server.wm.utils.InsetUtils; -  import com.google.android.collect.Sets; -  import java.io.PrintWriter;  import java.util.ArrayList; @@ -93,6 +90,7 @@ public class RecentsAnimationController implements DeathRecipient {      // The recents component app token that is shown behind the visibile tasks      private AppWindowToken mTargetAppToken; +    private int mTargetActivityType;      private Rect mMinimizedHomeBounds = new Rect();      // We start the RecentsAnimationController in a pending-start state since we need to wait for @@ -259,23 +257,37 @@ public class RecentsAnimationController implements DeathRecipient {          mDisplayId = displayId;      } +    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) { +        initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds); +    } +      /**       * Initializes the recents animation controller. This is a separate call from the constructor       * because it may call cancelAnimation() which needs to properly clean up the controller       * in the window manager.       */ -    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) { -        // Make leashes for each of the visible tasks and add it to the recents animation to be -        // started -        final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); +    @VisibleForTesting +    void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) { +        mTargetActivityType = targetActivityType; + +        // Make leashes for each of the visible/target tasks and add it to the recents animation to +        // be started          final ArrayList<Task> visibleTasks = dc.getVisibleTasks(); +        final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType); +        if (targetStack != null) { +            for (int i = targetStack.getChildCount() - 1; i >= 0; i--) { +                final Task t = targetStack.getChildAt(i); +                if (!visibleTasks.contains(t)) { +                    visibleTasks.add(t); +                } +            } +        }          final int taskCount = visibleTasks.size();          for (int i = 0; i < taskCount; i++) {              final Task task = visibleTasks.get(i);              final WindowConfiguration config = task.getWindowConfiguration();              if (config.tasksAreFloating() -                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY -                    || config.getActivityType() == targetActivityType) { +                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {                  continue;              }              addAnimation(task, !recentTaskIds.get(task.mTaskId)); @@ -586,7 +598,10 @@ public class RecentsAnimationController implements DeathRecipient {              final Rect insets = new Rect();              mainWindow.getContentInsets(insets);              InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets()); -            mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash, +            final int mode = topApp.getActivityType() == mTargetActivityType +                    ? MODE_OPENING +                    : MODE_CLOSING; +            mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,                      !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,                      insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,                      mTask.getWindowConfiguration(), mIsRecentTaskInvisible); @@ -594,11 +609,6 @@ public class RecentsAnimationController implements DeathRecipient {          }          @Override -        public boolean getDetachWallpaper() { -            return false; -        } - -        @Override          public boolean getShowWallpaper() {              return false;          } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 00422e3497be..8ec0a014e4a9 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -325,11 +325,6 @@ class RemoteAnimationController implements DeathRecipient {          }          @Override -        public boolean getDetachWallpaper() { -            return false; -        } - -        @Override          public boolean getShowWallpaper() {              return false;          } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index d92818ac611c..a9571be9599d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -48,7 +48,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SU  import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;  import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;  import static com.android.server.wm.WindowManagerService.logSurface; -import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;  import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;  import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;  import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING; @@ -91,7 +90,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {      private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;      private static final int SET_USER_ACTIVITY_TIMEOUT = 2; -    private boolean mWallpaperForceHidingChanged = false;      private Object mLastWindowFreezeSource = null;      private Session mHoldScreen = null;      private float mScreenBrightness = -1; @@ -626,18 +624,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {              recentsAnimationController.checkAnimationReady(mWallpaperController);          } -        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0 -                && !mService.mAppTransition.isReady()) { -            // At this point, there was a window with a wallpaper that was force hiding other -            // windows behind it, but now it is going away. This may be simple -- just animate away -            // the wallpaper and its window -- or it may be hard -- the wallpaper now needs to be -            // shown behind something that was hidden. -            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT; -            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats( -                    "after animateAwayWallpaperLocked", defaultDisplay.pendingLayoutChanges); -        } -        mWallpaperForceHidingChanged = false; -          if (mWallpaperMayChange) {              if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");              defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -961,10 +947,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {              mWallpaperMayChange = true;              doRequest = true;          } -        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) { -            mWallpaperForceHidingChanged = true; -            doRequest = true; -        }          if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {              mOrientationChangeComplete = false;          } else { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cc23ab6f77d9..6aa0e0144c40 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -561,9 +561,10 @@ class Task extends WindowContainer<AppWindowToken> {      @Override      public SurfaceControl getAnimationLeashParent() { -        // Reparent to the animation layer so that we aren't clipped by the non-minimized -        // stack bounds, currently we only animate the task for the recents animation -        return getAppAnimationLayer(ANIMATION_LAYER_STANDARD); +        // Currently, only the recents animation will create animation leashes for tasks. In this +        // case, reparent the task to the home animation layer while it is being animated to allow +        // the home activity to reorder the app windows relative to its own. +        return getAppAnimationLayer(ANIMATION_LAYER_HOME);      }      boolean isTaskAnimating() { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 2b8493749c79..00cacebe2960 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -1070,11 +1070,8 @@ public class TaskStack extends WindowContainer<Task> implements      }      void setAnimationBackground(WindowStateAnimator winAnimator, int color) { -        int animLayer = winAnimator.mAnimLayer; -        if (mAnimationBackgroundAnimator == null -                || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { +        if (mAnimationBackgroundAnimator == null) {              mAnimationBackgroundAnimator = winAnimator; -            animLayer = mDisplayContent.getLayerForAnimationBackground(winAnimator);              showAnimationSurface(((color >> 24) & 0xff) / 255f);          }      } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 3d349ce34d6b..a448f97306f0 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -120,13 +120,11 @@ class WallpaperController {          }          mFindResults.resetTopWallpaper = true; -        if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { +        if (w.mAppToken != null && w.mAppToken.isHidden() && !w.mAppToken.isSelfAnimating()) { +              // If this window's app token is hidden and not animating, it is of no interest to us. -            if (w.mAppToken.isHidden() && !w.mAppToken.isSelfAnimating()) { -                if (DEBUG_WALLPAPER) Slog.v(TAG, -                        "Skipping hidden and not animating token: " + w); -                return false; -            } +            if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w); +            return false;          }          if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()                  + " mDrawState=" + w.mWinAnimator.mDrawState); @@ -177,7 +175,7 @@ class WallpaperController {                  && (mWallpaperTarget == w || w.isDrawFinishedLw())) {              if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);              mFindResults.setWallpaperTarget(w); -            if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { +            if (w == mWallpaperTarget && w.isAnimating()) {                  // The current wallpaper target is animating, so we'll look behind it for                  // another possible target and figure out what is going on later.                  if (DEBUG_WALLPAPER) Slog.v(TAG, @@ -185,10 +183,6 @@ class WallpaperController {              }              // Found a target! End search.              return true; -        } else if (w == winAnimator.mWindowDetachedWallpaper) { -            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, -                    "Found animating detached wallpaper target win: " + w); -            mFindResults.setUseTopWallpaperAsTarget(true);          }          return false;      }; @@ -243,7 +237,7 @@ class WallpaperController {      }      boolean isWallpaperTargetAnimating() { -        return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimationSet() +        return mWallpaperTarget != null && mWallpaperTarget.isAnimating()                  && (mWallpaperTarget.mAppToken == null                          || !mWallpaperTarget.mAppToken.isWaitingForTransitionStart());      } diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index ddda027595da..e15b783b5606 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -138,7 +138,7 @@ class WallpaperWindowToken extends WindowToken {              wallpaper.dispatchWallpaperVisibility(visible);              if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " -                    + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); +                    + wallpaper);          }      } diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 825255e556ff..98c77ac719f9 100644 --- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java +++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java @@ -72,11 +72,6 @@ public class WindowAnimationSpec implements AnimationSpec {      }      @Override -    public boolean getDetachWallpaper() { -        return mAnimation.getDetachWallpaper(); -    } - -    @Override      public boolean getShowWallpaper() {          return mAnimation.getShowWallpaper();      } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 793ffce2466e..ad0b8ece7a80 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -58,17 +58,6 @@ public class WindowAnimator {      /** Time of current animation step. Reset on each iteration */      long mCurrentTime; -    boolean mAppWindowAnimating; -    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this -     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ -    int mAnimTransactionSequence; - -    /** Window currently running an animation that has requested it be detached -     * from the wallpaper.  This means we need to ensure the wallpaper is -     * visible behind it in case it animates in a way that would allow it to be -     * seen. If multiple windows satisfy this, use the lowest window. */ -    WindowState mWindowDetachedWallpaper = null; -      int mBulkUpdateParams = 0;      Object mLastWindowFreezeSource; @@ -191,9 +180,8 @@ public class WindowAnimator {                      // Update animations of all applications, including those                      // associated with exiting/removed apps -                    ++mAnimTransactionSequence; -                    dc.updateWindowsForAnimator(this); -                    dc.updateWallpaperForAnimator(this); +                    dc.updateWindowsForAnimator(); +                    dc.updateBackgroundForAnimator();                      dc.prepareSurfaces();                  } @@ -284,9 +272,6 @@ public class WindowAnimator {          if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {              builder.append(" WALLPAPER_MAY_CHANGE");          } -        if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) { -            builder.append(" FORCE_HIDING_CHANGED"); -        }          if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {              builder.append(" ORIENTATION_CHANGE_COMPLETE");          } @@ -317,8 +302,6 @@ public class WindowAnimator {          pw.println();          if (dumpAll) { -            pw.print(prefix); pw.print("mAnimTransactionSequence="); -                    pw.print(mAnimTransactionSequence);              pw.print(prefix); pw.print("mCurrentTime=");                      pw.println(TimeUtils.formatUptime(mCurrentTime));          } @@ -327,10 +310,6 @@ public class WindowAnimator {                      pw.print(Integer.toHexString(mBulkUpdateParams));                      pw.println(bulkUpdateParamsToString(mBulkUpdateParams));          } -        if (mWindowDetachedWallpaper != null) { -            pw.print(prefix); pw.print("mWindowDetachedWallpaper="); -                pw.println(mWindowDetachedWallpaper); -        }      }      int getPendingLayoutChanges(final int displayId) { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index e86093952474..4883f972f1e5 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -42,10 +42,8 @@ import android.view.MagnificationSpec;  import android.view.SurfaceControl;  import android.view.SurfaceControl.Builder;  import android.view.SurfaceSession; -  import com.android.internal.util.ToBooleanFunction;  import com.android.server.wm.SurfaceAnimator.Animatable; -  import java.io.PrintWriter;  import java.util.Comparator;  import java.util.LinkedList; @@ -71,7 +69,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<      /**       * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME} -     * activities that happens below all {@link TaskStack}s. +     * activities and all activities that are being controlled by the recents animation. This +     * layer is generally below all {@link TaskStack}s.       */      static final int ANIMATION_LAYER_HOME = 2; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7caa7aedb873..942e47b4725f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -227,6 +227,7 @@ import android.view.WindowManagerGlobal;  import android.view.WindowManagerPolicyConstants.PointerEventListener;  import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.os.IResultReceiver;  import com.android.internal.policy.IKeyguardDismissCallback;  import com.android.internal.policy.IShortcutService; @@ -2208,7 +2209,7 @@ public class WindowManagerService extends IWindowManager.Stub          if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {              focusMayChange = isDefaultDisplay;              win.mAnimatingExit = true; -        } else if (win.mWinAnimator.isAnimationSet()) { +        } else if (win.isAnimating()) {              // Currently in a hide animation... turn this into              // an exit.              win.mAnimatingExit = true; @@ -2714,6 +2715,11 @@ public class WindowManagerService extends IWindowManager.Stub          }      } +    @VisibleForTesting +    void setRecentsAnimationController(RecentsAnimationController controller) { +        mRecentsAnimationController = controller; +    } +      public RecentsAnimationController getRecentsAnimationController() {          return mRecentsAnimationController;      } @@ -5568,11 +5574,7 @@ public class WindowManagerService extends IWindowManager.Stub                  if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS                          && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) { -                    final int prevImeAnimLayer = -                            displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;                      displayContent.assignWindowLayers(false /* setLayoutNeeded */); -                    imWindowChanged |= prevImeAnimLayer -                            != displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;                  }              } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 7161a70b08fe..a4bac31bbcee 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1364,7 +1364,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP      @Override      boolean hasContentToDisplay() {          if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE -                || (mWinAnimator.isAnimationSet() && !mService.mAppTransition.isTransitionSet()))) { +                || (isAnimating() && !mService.mAppTransition.isTransitionSet()))) {              return true;          } @@ -1443,9 +1443,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          final AppWindowToken atoken = mAppToken;          if (atoken != null) {              return ((!isParentWindowHidden() && !atoken.hiddenRequested) -                    || mWinAnimator.isAnimationSet()); +                    || isAnimating());          } -        return !isParentWindowHidden() || mWinAnimator.isAnimationSet(); +        return !isParentWindowHidden() || isAnimating();      }      /** @@ -1476,9 +1476,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {              return false;          } +        final boolean parentAndClientVisible = !isParentWindowHidden() +                && mViewVisibility == View.VISIBLE && !mToken.isHidden();          return mHasSurface && mPolicyVisibility && !mDestroying -                && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.isHidden()) -                        || mWinAnimator.isAnimationSet()); +                && (parentAndClientVisible || isAnimating());      }      // TODO: Another visibility method that was added late in the release to minimize risk. @@ -1508,7 +1509,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          final AppWindowToken atoken = mAppToken;          return isDrawnLw() && mPolicyVisibility                  && ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested)) -                        || mWinAnimator.isAnimationSet()); +                        || isAnimating());      }      /** @@ -1562,7 +1563,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          // to determine if it's occluding apps.          return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)                  || (mIsWallpaper && mWallpaperVisible)) -                && isDrawnLw() && !mWinAnimator.isAnimationSet(); +                && isDrawnLw() && !isAnimating();      }      @Override @@ -1849,7 +1850,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP                      + " mRemoveOnExit=" + mRemoveOnExit                      + " mHasSurface=" + mHasSurface                      + " surfaceShowing=" + mWinAnimator.getShown() -                    + " isAnimationSet=" + mWinAnimator.isAnimationSet() +                    + " animating=" + isAnimating()                      + " app-animation="                      + (mAppToken != null ? mAppToken.isSelfAnimating() : "false")                      + " mWillReplaceWindow=" + mWillReplaceWindow @@ -1916,7 +1917,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP                          mService.mAccessibilityController.onWindowTransitionLocked(this, transit);                      }                  } -                final boolean isAnimating = mWinAnimator.isAnimationSet() +                final boolean isAnimating = isAnimating()                          && (mAppToken == null || !mAppToken.isWaitingForTransitionStart());                  final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null                          && mAppToken.isLastWindow(this); @@ -2434,10 +2435,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);          if (doAnimation) {              if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility=" -                    + mPolicyVisibility + " isAnimationSet=" + mWinAnimator.isAnimationSet()); +                    + mPolicyVisibility + " animating=" + isAnimating());              if (!mToken.okToAnimate()) {                  doAnimation = false; -            } else if (mPolicyVisibility && !mWinAnimator.isAnimationSet()) { +            } else if (mPolicyVisibility && !isAnimating()) {                  // Check for the case where we are currently visible and                  // not animating; we do not want to do animation at such a                  // point to become visible when we already are. @@ -2476,7 +2477,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          }          if (doAnimation) {              mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false); -            if (!mWinAnimator.isAnimationSet()) { +            if (!isAnimating()) {                  doAnimation = false;              }          } @@ -3216,10 +3217,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP                      + " mWallpaperVisible=" + mWallpaperVisible);          }          if (dumpAll) { -            pw.println(prefix + "mBaseLayer=" + mBaseLayer -                    + " mSubLayer=" + mSubLayer -                    + " mAnimLayer=" + mLayer + "=" + mWinAnimator.mAnimLayer -                    + " mLastLayer=" + mWinAnimator.mLastLayer); +            pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer); +                    pw.print(" mSubLayer="); pw.print(mSubLayer);          }          if (dumpAll) {              pw.println(prefix + "mToken=" + mToken); @@ -3697,7 +3696,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP                      + " tok.hiddenRequested="                      + (mAppToken != null && mAppToken.hiddenRequested)                      + " tok.hidden=" + (mAppToken != null && mAppToken.isHidden()) -                    + " animationSet=" + mWinAnimator.isAnimationSet() +                    + " animating=" + isAnimating()                      + " tok animating="                      + (mAppToken != null && mAppToken.isSelfAnimating())                      + " Callers=" + Debug.getCallers(4)); @@ -3749,18 +3748,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          return windowInfo;      } -    int getHighestAnimLayer() { -        int highest = mWinAnimator.mAnimLayer; -        for (int i = mChildren.size() - 1; i >= 0; i--) { -            final WindowState c = mChildren.get(i); -            final int childLayer = c.getHighestAnimLayer(); -            if (childLayer > highest) { -                highest = childLayer; -            } -        } -        return highest; -    } -      @Override      boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {          if (mChildren.isEmpty()) { @@ -4110,25 +4097,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          }          if (DEBUG_VISIBILITY) {              Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw() -                    + ", isAnimationSet=" + mWinAnimator.isAnimationSet()); +                    + ", animating=" + isAnimating());              if (!isDrawnLw()) {                  Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController                          + " pv=" + mPolicyVisibility                          + " mDrawState=" + mWinAnimator.mDrawState                          + " ph=" + isParentWindowHidden()                          + " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false) -                        + " a=" + mWinAnimator.isAnimationSet()); +                        + " a=" + isAnimating());              }          }          results.numInteresting++;          if (isDrawnLw()) {              results.numDrawn++; -            if (!mWinAnimator.isAnimationSet()) { +            if (!isAnimating()) {                  results.numVisible++;              }              results.nowGone = false; -        } else if (mWinAnimator.isAnimationSet()) { +        } else if (isAnimating()) {              results.nowGone = false;          }      } @@ -4535,7 +4522,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          updateSurfacePosition(getPendingTransaction());      } -    private void updateSurfacePosition(Transaction t) { +    @VisibleForTesting +    void updateSurfacePosition(Transaction t) {          if (mSurfaceControl == null) {              return;          } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 979149a854cb..2beb7887698e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -107,8 +107,6 @@ class WindowStateAnimator {      private final WallpaperController mWallpaperControllerLocked;      boolean mAnimationIsEntrance; -    int mAnimLayer; -    int mLastLayer;      /**       * Set when we have changed the size of the surface, to know that @@ -135,7 +133,6 @@ class WindowStateAnimator {      float mLastAlpha = 0;      Rect mTmpClipRect = new Rect(); -    Rect mTmpFinalClipRect = new Rect();      Rect mLastClipRect = new Rect();      Rect mLastFinalClipRect = new Rect();      Rect mTmpStackBounds = new Rect(); @@ -162,8 +159,6 @@ class WindowStateAnimator {       * window is first added or shown, cleared when the callback has been made. */      boolean mEnteringAnimation; -    private boolean mAnimationStartDelayed; -      private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();      /** The pixel format of the underlying SurfaceControl */ @@ -253,13 +248,6 @@ class WindowStateAnimator {          mWallpaperControllerLocked = mService.mRoot.mWallpaperController;      } -    /** -     * Is the window or its container currently set to animate or currently animating? -     */ -    boolean isAnimationSet() { -        return mWin.isAnimating(); -    } -      void cancelExitAnimationForNextAnimationLocked() {          if (DEBUG_ANIM) Slog.d(TAG,                  "cancelExitAnimationForNextAnimationLocked: " + mWin); @@ -275,10 +263,6 @@ class WindowStateAnimator {                          + ", reportedVisible="                          + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false)); -        if (mAnimator.mWindowDetachedWallpaper == mWin) { -            mAnimator.mWindowDetachedWallpaper = null; -        } -          mWin.checkPolicyVisibilityChange();          final DisplayContent displayContent = mWin.getDisplayContent();          if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) { @@ -288,7 +272,6 @@ class WindowStateAnimator {                  displayContent.setLayoutNeeded();              }          } -          mWin.onExitAnimationDone();          final int displayId = mWin.getDisplayId();          int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM; @@ -539,14 +522,13 @@ class WindowStateAnimator {          }          if (WindowManagerService.localLOGV) Slog.v(TAG, "Got surface: " + mSurfaceController -                + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top -                + ", animLayer=" + mAnimLayer); +                + ", set left=" + w.getFrameLw().left + " top=" + w.getFrameLw().top);          if (SHOW_LIGHT_TRANSACTIONS) {              Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");              WindowManagerService.logSurface(w, "CREATE pos=("                      + w.getFrameLw().left + "," + w.getFrameLw().top + ") (" -                    + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false); +                    + width + "x" + height + ")" + " HIDE", false);          }          mLastHidden = true; @@ -1133,8 +1115,7 @@ class WindowStateAnimator {                  if (DEBUG_ORIENTATION) Slog.v(TAG,                          "Orientation change skips hidden " + w);              } -        } else if (mLastLayer != mAnimLayer -                || mLastAlpha != mShownAlpha +        } else if (mLastAlpha != mShownAlpha                  || mLastDsDx != mDsDx                  || mLastDtDx != mDtDx                  || mLastDsDy != mDsDy @@ -1144,7 +1125,6 @@ class WindowStateAnimator {                  || mLastHidden) {              displayed = true;              mLastAlpha = mShownAlpha; -            mLastLayer = mAnimLayer;              mLastDsDx = mDsDx;              mLastDtDx = mDtDx;              mLastDsDy = mDsDy; @@ -1153,7 +1133,7 @@ class WindowStateAnimator {              w.mLastVScale = w.mVScale;              if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,                      "controller=" + mSurfaceController + -                    "alpha=" + mShownAlpha + " layer=" + mAnimLayer +                    "alpha=" + mShownAlpha                      + " matrix=[" + mDsDx + "*" + w.mHScale                      + "," + mDtDx + "*" + w.mVScale                      + "][" + mDtDy + "*" + w.mHScale @@ -1197,7 +1177,7 @@ class WindowStateAnimator {                  w.mToken.hasVisible = true;              }          } else { -            if (DEBUG_ANIM && isAnimationSet()) { +            if (DEBUG_ANIM && mWin.isAnimating()) {                  Slog.v(TAG, "prepareSurface: No changes in animation for " + this);              }              displayed = true; @@ -1407,7 +1387,7 @@ class WindowStateAnimator {          }          Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); -        return isAnimationSet(); +        return mWin.isAnimating();      }      void writeToProto(ProtoOutputStream proto, long fieldId) { @@ -1460,9 +1440,6 @@ class WindowStateAnimator {                      pw.print(" mDtDy="); pw.print(mDtDy);                      pw.print(" mDsDy="); pw.println(mDsDy);          } -        if (mAnimationStartDelayed) { -            pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed); -        }      }      @Override @@ -1520,10 +1497,6 @@ class WindowStateAnimator {          mChildrenDetached = true;      } -    int getLayer() { -        return mLastLayer; -    } -      void setOffsetPositionForStackResize(boolean offsetPositionForStackResize) {          mOffsetPositionForStackResize = offsetPositionForStackResize;      } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index d6f9ac3a3ab9..080a3a269947 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -92,19 +92,12 @@ class WindowSurfacePlacer {      static final int SET_UPDATE_ROTATION                = 1 << 0;      static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1; -    static final int SET_FORCE_HIDING_CHANGED           = 1 << 2; -    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3; -    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 4; +    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 2; +    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 3;      private boolean mTraversalScheduled;      private int mDeferDepth = 0; -    private static final class LayerAndToken { -        public int layer; -        public AppWindowToken token; -    } -    private final LayerAndToken mTmpLayerAndToken = new LayerAndToken(); -      private final SparseIntArray mTempTransitionReasons = new SparseIntArray();      private final Runnable mPerformSurfacePlacement; @@ -299,10 +292,16 @@ class WindowSurfacePlacer {          // done behind a dream window.          final ArraySet<Integer> activityTypes = collectActivityTypes(mService.mOpeningApps,                  mService.mClosingApps); -        final AppWindowToken animLpToken = mService.mPolicy.allowAppAnimationsLw() +        final boolean allowAnimations = mService.mPolicy.allowAppAnimationsLw(); +        final AppWindowToken animLpToken = allowAnimations                  ? findAnimLayoutParamsToken(transit, activityTypes)                  : null; - +        final AppWindowToken topOpeningApp = allowAnimations +                ? getTopApp(mService.mOpeningApps, false /* ignoreHidden */) +                : null; +        final AppWindowToken topClosingApp = allowAnimations +                ? getTopApp(mService.mClosingApps, false /* ignoreHidden */) +                : null;          final LayoutParams animLp = getAnimLp(animLpToken);          overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes); @@ -314,17 +313,14 @@ class WindowSurfacePlacer {          try {              processApplicationsAnimatingInPlace(transit); -            mTmpLayerAndToken.token = null; -            handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); -            final AppWindowToken topClosingApp = mTmpLayerAndToken.token; -            final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, -                    voiceInteraction); +            handleClosingApps(transit, animLp, voiceInteraction); +            handleOpeningApps(transit, animLp, voiceInteraction);              mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp);              final int flags = mService.mAppTransition.getTransitFlags(); -            layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, -                    topClosingApp, mService.mOpeningApps, mService.mClosingApps); +            layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, topClosingApp, +                    mService.mOpeningApps, mService.mClosingApps);              handleNonAppWindowsInTransition(transit, flags);              mService.mAppTransition.postAnimationCallback();              mService.mAppTransition.clear(); @@ -451,10 +447,7 @@ class WindowSurfacePlacer {          return false;      } -    private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp, -            boolean voiceInteraction) { -        AppWindowToken topOpeningApp = null; -        int topOpeningLayer = Integer.MIN_VALUE; +    private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {          final int appsCount = mService.mOpeningApps.size();          for (int i = 0; i < appsCount; i++) {              AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); @@ -479,24 +472,15 @@ class WindowSurfacePlacer {                          "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");              } -            if (animLp != null) { -                final int layer = wtoken.getHighestAnimLayer(); -                if (topOpeningApp == null || layer > topOpeningLayer) { -                    topOpeningApp = wtoken; -                    topOpeningLayer = layer; -                } -            }              if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {                  wtoken.attachThumbnailAnimation();              } else if (mService.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {                  wtoken.attachCrossProfileAppsThumbnailAnimation();              }          } -        return topOpeningApp;      } -    private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction, -            LayerAndToken layerAndToken) { +    private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {          final int appsCount;          appsCount = mService.mClosingApps.size();          for (int i = 0; i < appsCount; i++) { @@ -519,13 +503,6 @@ class WindowSurfacePlacer {                  wtoken.getController().removeStartingWindow();              } -            if (animLp != null) { -                int layer = wtoken.getHighestAnimLayer(); -                if (layerAndToken.token == null || layer > layerAndToken.layer) { -                    layerAndToken.token = wtoken; -                    layerAndToken.layer = layer; -                } -            }              if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) {                  wtoken.attachThumbnailAnimation();              } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 8972c3891ec1..fefd305bc6d6 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -163,7 +163,7 @@ class WindowToken extends WindowContainer<WindowState> {          for (int i = 0; i < count; i++) {              final WindowState win = mChildren.get(i); -            if (win.mWinAnimator.isAnimationSet()) { +            if (win.isAnimating()) {                  delayed = true;              }              changed |= win.onSetAppExiting(); @@ -235,18 +235,6 @@ class WindowToken extends WindowContainer<WindowState> {          return false;      } -    int getHighestAnimLayer() { -        int highest = -1; -        for (int j = 0; j < mChildren.size(); j++) { -            final WindowState w = mChildren.get(j); -            final int wLayer = w.getHighestAnimLayer(); -            if (wLayer > highest) { -                highest = wLayer; -            } -        } -        return highest; -    } -      AppWindowToken asAppWindowToken() {          // TODO: Not sure if this is the best way to handle this vs. using instanceof and casting.          // I am not an app window token! diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index becde7311607..157b6349f4ee 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -37,6 +37,7 @@ cc_library_static {          "com_android_server_locksettings_SyntheticPasswordManager.cpp",          "com_android_server_net_NetworkStatsService.cpp",          "com_android_server_power_PowerManagerService.cpp", +        "com_android_server_security_VerityUtils.cpp",          "com_android_server_SerialService.cpp",          "com_android_server_storage_AppFuseBridge.cpp",          "com_android_server_SystemServer.cpp", @@ -89,7 +90,6 @@ cc_defaults {          "libsensorservicehidl",          "libgui",          "libusbhost", -        "libsuspend",          "libtinyalsa",          "libEGL",          "libGLESv2", @@ -121,6 +121,7 @@ cc_defaults {          "android.hardware.vr@1.0",          "android.frameworks.schedulerservice@1.0",          "android.frameworks.sensorservice@1.0", +        "android.system.suspend@1.0",      ],      static_libs: [ diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index 02ad6c71b586..0ff60e44b0ce 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -30,6 +30,8 @@  #include <android/hardware/power/1.0/IPower.h>  #include <android/hardware/power/1.1/IPower.h> +#include <android/system/suspend/1.0/ISystemSuspend.h> +#include <android/system/suspend/1.0/ISystemSuspendCallback.h>  #include <android_runtime/AndroidRuntime.h>  #include <jni.h> @@ -39,7 +41,6 @@  #include <log/log.h>  #include <utils/misc.h>  #include <utils/Log.h> -#include <suspend/autosuspend.h>  using android::hardware::Return;  using android::hardware::Void; @@ -49,6 +50,8 @@ using android::hardware::power::V1_0::Status;  using android::hardware::power::V1_1::PowerStateSubsystem;  using android::hardware::power::V1_1::PowerStateSubsystemSleepState;  using android::hardware::hidl_vec; +using android::system::suspend::V1_0::ISystemSuspend; +using android::system::suspend::V1_0::ISystemSuspendCallback;  using IPowerV1_1 = android::hardware::power::V1_1::IPower;  using IPowerV1_0 = android::hardware::power::V1_0::IPower; @@ -63,6 +66,7 @@ static sem_t wakeup_sem;  extern sp<IPowerV1_0> getPowerHalV1_0();  extern sp<IPowerV1_1> getPowerHalV1_1();  extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName); +extern sp<ISystemSuspend> getSuspendHal();  // Java methods used in getLowPowerStats  static jmethodID jgetAndUpdatePlatformState = NULL; @@ -70,16 +74,19 @@ static jmethodID jgetSubsystem = NULL;  static jmethodID jputVoter = NULL;  static jmethodID jputState = NULL; -static void wakeup_callback(bool success) -{ -    ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted"); -    int ret = sem_post(&wakeup_sem); -    if (ret < 0) { -        char buf[80]; -        strerror_r(errno, buf, sizeof(buf)); -        ALOGE("Error posting wakeup sem: %s\n", buf); +class WakeupCallback : public ISystemSuspendCallback { +public: +    Return<void> notifyWakeup(bool success) override { +        ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted"); +        int ret = sem_post(&wakeup_sem); +        if (ret < 0) { +            char buf[80]; +            strerror_r(errno, buf, sizeof(buf)); +            ALOGE("Error posting wakeup sem: %s\n", buf); +        } +        return Void();      } -} +};  static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)  { @@ -101,11 +108,14 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)              return -1;          }          ALOGV("Registering callback..."); -        autosuspend_set_wakeup_callback(&wakeup_callback); +        sp<ISystemSuspend> suspendHal = getSuspendHal(); +        suspendHal->registerCallback(new WakeupCallback());      }      // Wait for wakeup.      ALOGV("Waiting for wakeup..."); +    // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup +    // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events.      int ret = sem_wait(&wakeup_sem);      if (ret < 0) {          char buf[80]; diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index b2d35d4153a0..0c9b5f4999a0 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -19,6 +19,7 @@  //#define LOG_NDEBUG 0  #include <android/hardware/power/1.1/IPower.h> +#include <android/system/suspend/1.0/ISystemSuspend.h>  #include <nativehelper/JNIHelp.h>  #include "jni.h" @@ -35,7 +36,7 @@  #include <utils/Log.h>  #include <hardware/power.h>  #include <hardware_legacy/power.h> -#include <suspend/autosuspend.h> +#include <hidl/ServiceManagement.h>  #include "com_android_server_power_PowerManagerService.h" @@ -44,6 +45,9 @@ using android::hardware::Void;  using android::hardware::power::V1_0::PowerHint;  using android::hardware::power::V1_0::Feature;  using android::String8; +using android::system::suspend::V1_0::ISystemSuspend; +using android::system::suspend::V1_0::IWakeLock; +using android::system::suspend::V1_0::WakeLockType;  using IPowerV1_1 = android::hardware::power::V1_1::IPower;  using IPowerV1_0 = android::hardware::power::V1_0::IPower; @@ -171,6 +175,46 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t      }  } +static sp<ISystemSuspend> gSuspendHal = nullptr; +static sp<IWakeLock> gSuspendBlocker = nullptr; +static std::mutex gSuspendMutex; + +// Assume SystemSuspend HAL is always alive. +// TODO: Force device to restart if SystemSuspend HAL dies. +sp<ISystemSuspend> getSuspendHal() { +    static std::once_flag suspendHalFlag; +    std::call_once(suspendHalFlag, [](){ +        ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, "default"); +        gSuspendHal = ISystemSuspend::getService(); +        assert(gSuspendHal != nullptr); +    }); +    return gSuspendHal; +} + +void enableAutoSuspend() { +    static bool enabled = false; + +    std::lock_guard<std::mutex> lock(gSuspendMutex); +    if (!enabled) { +        sp<ISystemSuspend> suspendHal = getSuspendHal(); +        suspendHal->enableAutosuspend(); +        enabled = true; +    } +    if (gSuspendBlocker) { +        gSuspendBlocker->release(); +        gSuspendBlocker.clear(); +    } +} + +void disableAutoSuspend() { +    std::lock_guard<std::mutex> lock(gSuspendMutex); +    if (!gSuspendBlocker) { +        sp<ISystemSuspend> suspendHal = getSuspendHal(); +        gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL, +                "PowerManager.SuspendLockout"); +    } +} +  // ----------------------------------------------------------------------------  static void nativeInit(JNIEnv* env, jobject obj) { @@ -207,13 +251,13 @@ static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean  static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {      if (enable) {          android::base::Timer t; -        autosuspend_enable(); +        enableAutoSuspend();          if (t.duration() > 100ms) {              ALOGD("Excessive delay in autosuspend_enable() while turning screen off");          }      } else {          android::base::Timer t; -        autosuspend_disable(); +        disableAutoSuspend();          if (t.duration() > 100ms) {              ALOGD("Excessive delay in autosuspend_disable() while turning screen on");          } diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp new file mode 100644 index 000000000000..d0f173b572c8 --- /dev/null +++ b/services/core/jni/com_android_server_security_VerityUtils.cpp @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#define LOG_TAG "VerityUtils" + +#include <nativehelper/JNIHelp.h> +#include "jni.h" +#include <utils/Log.h> + +#include <string.h> + +// TODO(112037636): Always include once fsverity.h is upstreamed and backported. +#define HAS_FSVERITY 0 + +#if HAS_FSVERITY +#include <linux/fsverity.h> +#endif + +namespace android { + +namespace { + +class JavaByteArrayHolder { +  public: +    static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) { +        return new JavaByteArrayHolder(env, size); +    } + +    jbyte* getRaw() { +        return mElements; +    } + +    jbyteArray release() { +        mEnv->ReleaseByteArrayElements(mBytes, mElements, 0); +        mElements = nullptr; +        return mBytes; +    } + +  private: +    JavaByteArrayHolder(JNIEnv* env, jsize size) { +        mEnv = env; +        mBytes = mEnv->NewByteArray(size); +        mElements = mEnv->GetByteArrayElements(mBytes, nullptr); +        memset(mElements, 0, size); +    } + +    virtual ~JavaByteArrayHolder() { +        LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released"); +    } + +    JNIEnv* mEnv; +    jbyteArray mBytes; +    jbyte* mElements; +}; + +jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { +#if HAS_FSVERITY +    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); +    fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw()); + +    memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic)); +    desc->major_version = 1; +    desc->minor_version = 0; +    desc->log_data_blocksize = 12; +    desc->log_tree_blocksize = 12; +    desc->data_algorithm = FS_VERITY_ALG_SHA256; +    desc->tree_algorithm = FS_VERITY_ALG_SHA256; +    desc->flags = 0; +    desc->orig_file_size = fileSize; +    desc->auth_ext_count = 1; + +    return raii->release(); +#else +    LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); +    return 0; +#endif  // HAS_FSVERITY +} + +jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, +        jint extensionDataSize) { +#if HAS_FSVERITY +    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); +    fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw()); + +    ext->length = sizeof(fsverity_extension) + extensionDataSize; +    ext->type = extensionId; + +    return raii->release(); +#else +    LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); +    return 0; +#endif  // HAS_FSVERITY +} + +jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, +        jint offsetToDescriptorHead) { +#if HAS_FSVERITY +    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); +    fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw()); + +    footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer); +    memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); + +    return raii->release(); +#else +    LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); +    return 0; +#endif  // HAS_FSVERITY +} + +const JNINativeMethod sMethods[] = { +    { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, +    { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension }, +    { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter }, +}; + +}  // namespace + +int register_android_server_security_VerityUtils(JNIEnv* env) { +    return jniRegisterNativeMethods(env, +            "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods)); +} + +}  // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index bb6e6840f3b4..918f57e2945e 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -54,6 +54,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env);  int register_android_server_GraphicsStatsService(JNIEnv* env);  int register_android_hardware_display_DisplayViewport(JNIEnv* env);  int register_android_server_net_NetworkStatsService(JNIEnv* env); +int register_android_server_security_VerityUtils(JNIEnv* env);  };  using namespace android; @@ -101,5 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)      register_android_server_GraphicsStatsService(env);      register_android_hardware_display_DisplayViewport(env);      register_android_server_net_NetworkStatsService(env); +    register_android_server_security_VerityUtils(env);      return JNI_VERSION_1_4;  } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java index 0c0ce8dd5174..a8b9b0c910ac 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java @@ -18,27 +18,23 @@ package com.android.server.devicepolicy;  import android.Manifest.permission;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.app.admin.DeviceAdminService;  import android.app.admin.DevicePolicyManager;  import android.app.admin.IDeviceAdminService;  import android.content.ComponentName;  import android.content.Context; -import android.content.Intent; -import android.content.pm.ParceledListSlice; -import android.content.pm.ResolveInfo;  import android.content.pm.ServiceInfo;  import android.os.Handler;  import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log;  import android.util.Slog;  import android.util.SparseArray;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.os.BackgroundThread;  import com.android.server.am.PersistentConnection; +import com.android.server.appbinding.AppBindingUtils;  import java.io.PrintWriter; -import java.util.List;  /**   * Manages connections to persistent services in owner packages. @@ -74,6 +70,11 @@ public class DeviceAdminServiceController {          }          @Override +        protected int getBindFlags() { +            return Context.BIND_FOREGROUND_SERVICE; +        } + +        @Override          protected IDeviceAdminService asInterface(IBinder binder) {              return IDeviceAdminService.Stub.asInterface(binder);          } @@ -100,40 +101,14 @@ public class DeviceAdminServiceController {       */      @Nullable      private ServiceInfo findService(@NonNull String packageName, int userId) { -        final Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE); -        intent.setPackage(packageName); - -        try { -            final ParceledListSlice<ResolveInfo> pls = mInjector.getIPackageManager() -                    .queryIntentServices(intent, null, /* flags=*/ 0, userId); -            if (pls == null) { -                return null; -            } -            final List<ResolveInfo> list = pls.getList(); -            if (list.size() == 0) { -                return null; -            } -            // Note if multiple services are found, that's an error, even if only one of them -            // is exported. -            if (list.size() > 1) { -                Log.e(TAG, "More than one DeviceAdminService's found in package " -                        + packageName -                        + ".  They'll all be ignored."); -                return null; -            } -            final ServiceInfo si = list.get(0).serviceInfo; - -            if (!permission.BIND_DEVICE_ADMIN.equals(si.permission)) { -                Log.e(TAG, "DeviceAdminService " -                        + si.getComponentName().flattenToShortString() -                        + " must be protected with " + permission.BIND_DEVICE_ADMIN -                        + "."); -                return null; -            } -            return si; -        } catch (RemoteException e) { -        } -        return null; +        return AppBindingUtils.findService( +                packageName, +                userId, +                DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE, +                permission.BIND_DEVICE_ADMIN, +                DeviceAdminService.class, +                mInjector.getIPackageManager(), +                new StringBuilder() /* ignore error message */);      }      /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e76afa3c144a..eeb4ad32408c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10106,13 +10106,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {              if (setting.equals(Settings.Secure.INSTALL_NON_MARKET_APPS)) {                  if (getTargetSdk(who.getPackageName(), callingUserId) >= Build.VERSION_CODES.O) {                      throw new UnsupportedOperationException(Settings.Secure.INSTALL_NON_MARKET_APPS -                            + " is deprecated. Please use the user restriction " -                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES + " instead."); +                            + " is deprecated. Please use one of the user restrictions " +                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES + " or " +                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY + " instead.");                  }                  if (!mUserManager.isManagedProfile(callingUserId)) {                      Slog.e(LOG_TAG, "Ignoring setSecureSetting request for "                              + setting + ". User restriction " -                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES +                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES + " or " +                            + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY                              + " should be used instead.");                  } else {                      try { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index fb95f5972cbb..b8241d03a78e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -65,6 +65,7 @@ import com.android.internal.util.EmergencyAffordanceManager;  import com.android.internal.widget.ILockSettings;  import com.android.server.am.ActivityManagerService;  import com.android.server.am.ActivityTaskManagerService; +import com.android.server.appbinding.AppBindingService;  import com.android.server.audio.AudioService;  import com.android.server.biometrics.BiometricService;  import com.android.server.broadcastradio.BroadcastRadioService; @@ -1710,6 +1711,10 @@ public final class SystemServer {              traceEnd();          } +        traceBeginAndSlog("AppServiceManager"); +        mSystemServiceManager.startService(AppBindingService.Lifecycle.class); +        traceEnd(); +          // It is now time to start up the app processes...          traceBeginAndSlog("MakeVibratorServiceReady"); diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java index f7bf393f367b..5a73a4e492ee 100644 --- a/services/net/java/android/net/util/SharedLog.java +++ b/services/net/java/android/net/util/SharedLog.java @@ -17,6 +17,7 @@  package android.net.util;  import android.annotation.NonNull; +import android.annotation.Nullable;  import android.text.TextUtils;  import android.util.LocalLog;  import android.util.Log; @@ -92,10 +93,17 @@ public class SharedLog {      }      /** -     * Log an error due to an exception, with the exception stacktrace. +     * Log an error due to an exception, with the exception stacktrace if provided. +     * +     * <p>The error and exception message appear in the shared log, but the stacktrace is only +     * logged in general log output (logcat).       */ -    public void e(@NonNull String msg, @NonNull Throwable e) { -        Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e); +    public void e(@NonNull String msg, @Nullable Throwable exception) { +        if (exception == null) { +            e(msg); +            return; +        } +        Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);      }      public void i(String msg) { diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index 8b5977144db1..78c0be42a448 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \      $(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \      $(call all-java-files-under, ../../core/java/android/app/backup) \      $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \ +    $(call all-java-files-under, ../../core/java/android/util/proto) \      ../../core/java/android/content/pm/PackageInfo.java \      ../../core/java/android/app/IBackupAgent.aidl \      ../../core/java/android/util/KeyValueSettingObserver.java \ diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java new file mode 100644 index 000000000000..383bf1d73416 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +import com.android.internal.util.Preconditions; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.base.Charsets; +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +// Include android.util.proto in addition to classes under test because the latest versions of +// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric. +@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"}) +@Presubmit +public class ChunkListingTest { +    private static final String CHUNK_A = "CHUNK_A"; +    private static final String CHUNK_B = "CHUNK_B"; +    private static final String CHUNK_C = "CHUNK_C"; + +    private static final int CHUNK_A_LENGTH = 256; +    private static final int CHUNK_B_LENGTH = 1024; +    private static final int CHUNK_C_LENGTH = 4055; + +    private ChunkHash mChunkHashA; +    private ChunkHash mChunkHashB; +    private ChunkHash mChunkHashC; + +    @Before +    public void setUp() throws Exception { +        mChunkHashA = getHash(CHUNK_A); +        mChunkHashB = getHash(CHUNK_B); +        mChunkHashC = getHash(CHUNK_C); +    } + +    @Test +    public void testHasChunk_whenChunkInListing_returnsTrue() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + +        boolean chunkAInList = chunkListing.hasChunk(mChunkHashA); +        boolean chunkBInList = chunkListing.hasChunk(mChunkHashB); +        boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + +        assertThat(chunkAInList).isTrue(); +        assertThat(chunkBInList).isTrue(); +        assertThat(chunkCInList).isTrue(); +    } + +    @Test +    public void testHasChunk_whenChunkNotInListing_returnsFalse() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); +        ChunkHash chunkHashEmpty = getHash(""); + +        boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); +        boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty); + +        assertThat(chunkCInList).isFalse(); +        assertThat(emptyChunkInList).isFalse(); +    } + +    @Test +    public void testGetChunkEntry_returnsEntryWithCorrectLength() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + +        ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); +        ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); +        ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + +        assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH); +        assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH); +        assertThat(entryC.getLength()).isEqualTo(CHUNK_C_LENGTH); +    } + +    @Test +    public void testGetChunkEntry_returnsEntryWithCorrectStart() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + +        ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); +        ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); +        ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + +        assertThat(entryA.getStart()).isEqualTo(0); +        assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH); +        assertThat(entryC.getStart()).isEqualTo(CHUNK_A_LENGTH + CHUNK_B_LENGTH); +    } + +    @Test +    public void testGetChunkEntry_returnsNullForNonExistentChunk() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + +        ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC); + +        assertThat(chunkEntryNonexistentChunk).isNull(); +    } + +    @Test +    public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception { +        ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); + +        ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto); + +        assertThat(chunkListing.getChunkCount()).isEqualTo(0); +    } + +    @Test +    public void testReadFromProto_returnsChunkListingWithCorrectSize() throws Exception { +        byte[] chunkListingProto = +                createChunkListingProto( +                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, +                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); + +        ChunkListing chunkListing = +                ChunkListing.readFromProto( +                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + +        assertThat(chunkListing.getChunkCount()).isEqualTo(3); +    } + +    private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) { +        Preconditions.checkArgument(hashes.length == lengths.length); +        ProtoOutputStream outputStream = new ProtoOutputStream(); + +        for (int i = 0; i < hashes.length; ++i) { +            writeToProtoOutputStream(outputStream, hashes[i], lengths[i]); +        } +        outputStream.flush(); + +        return outputStream.getBytes(); +    } + +    private void writeToProtoOutputStream(ProtoOutputStream out, ChunkHash chunkHash, int length) { +        long token = out.start(ChunksMetadataProto.ChunkListing.CHUNKS); +        out.write(ChunksMetadataProto.Chunk.HASH, chunkHash.getHash()); +        out.write(ChunksMetadataProto.Chunk.LENGTH, length); +        out.end(token); +    } + +    private ChunkHash getHash(String name) { +        return new ChunkHash( +                Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES)); +    } +} diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java new file mode 100644 index 000000000000..1dd7dc834f9e --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.base.Charsets; +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +// Include android.util.proto in addition to classes under test because the latest versions of +// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric. +@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"}) +@Presubmit +public class ChunkTest { +    private static final String CHUNK_A = "CHUNK_A"; +    private static final int CHUNK_A_LENGTH = 256; + +    private ChunkHash mChunkHashA; + +    @Before +    public void setUp() throws Exception { +        mChunkHashA = getHash(CHUNK_A); +    } + +    @Test +    public void testReadFromProto_readsCorrectly() throws Exception { +        ProtoOutputStream out = new ProtoOutputStream(); +        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); +        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); +        out.flush(); +        byte[] protoBytes = out.getBytes(); + +        Chunk chunk = +                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + +        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); +        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); +    } + +    @Test +    public void testReadFromProto_whenFieldsWrittenInReversedOrder_readsCorrectly() +            throws Exception { +        ProtoOutputStream out = new ProtoOutputStream(); +        // Write fields of Chunk proto in reverse order. +        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); +        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); +        out.flush(); +        byte[] protoBytes = out.getBytes(); + +        Chunk chunk = +                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + +        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); +        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); +    } + +    @Test +    public void testReadFromProto_whenEmptyProto_returnsEmptyHash() throws Exception { +        ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); + +        Chunk chunk = Chunk.readFromProto(emptyProto); + +        assertThat(chunk.getHash()).asList().hasSize(0); +        assertThat(chunk.getLength()).isEqualTo(0); +    } + +    @Test +    public void testReadFromProto_whenOnlyHashSet_returnsChunkWithOnlyHash() throws Exception { +        ProtoOutputStream out = new ProtoOutputStream(); +        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); +        out.flush(); +        byte[] protoBytes = out.getBytes(); + +        Chunk chunk = +                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + +        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); +        assertThat(chunk.getLength()).isEqualTo(0); +    } + +    @Test +    public void testReadFromProto_whenOnlyLengthSet_returnsChunkWithOnlyLength() throws Exception { +        ProtoOutputStream out = new ProtoOutputStream(); +        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); +        out.flush(); +        byte[] protoBytes = out.getBytes(); + +        Chunk chunk = +                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + +        assertThat(chunk.getHash()).isEqualTo(new byte[] {}); +        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); +    } + +    private ChunkHash getHash(String name) { +        return new ChunkHash( +                Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES)); +    } +} diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java new file mode 100644 index 000000000000..1cd1528b930c --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.primitives.Bytes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class EncryptedChunkOrderingTest { +    private static final byte[] TEST_BYTE_ARRAY_1 = new byte[] {1, 2, 3, 4, 5}; +    private static final byte[] TEST_BYTE_ARRAY_2 = new byte[] {5, 4, 3, 2, 1}; + +    @Test +    public void testEncryptedChunkOrdering_returnsValue() { +        EncryptedChunkOrdering encryptedChunkOrdering = +                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + +        byte[] bytes = encryptedChunkOrdering.encryptedChunkOrdering(); + +        assertThat(bytes) +                .asList() +                .containsExactlyElementsIn(Bytes.asList(TEST_BYTE_ARRAY_1)) +                .inOrder(); +    } + +    @Test +    public void testEquals() { +        EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); +        EncryptedChunkOrdering equalChunkOrdering1 = +                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); +        EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2); + +        assertThat(chunkOrdering1).isEqualTo(equalChunkOrdering1); +        assertThat(chunkOrdering1).isNotEqualTo(chunkOrdering2); +    } + +    @Test +    public void testHashCode() { +        EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); +        EncryptedChunkOrdering equalChunkOrdering1 = +                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); +        EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2); + +        int hash1 = chunkOrdering1.hashCode(); +        int equalHash1 = equalChunkOrdering1.hashCode(); +        int hash2 = chunkOrdering2.hashCode(); + +        assertThat(hash1).isEqualTo(equalHash1); +        assertThat(hash1).isNotEqualTo(hash2); +    } +} diff --git a/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java new file mode 100644 index 000000000000..373033500cde --- /dev/null +++ b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; + +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import java.io.IOException; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class AgentExceptionTest { +    @Test +    public void testTransitory_isTransitory() throws Exception { +        AgentException exception = AgentException.transitory(); + +        assertThat(exception.isTransitory()).isTrue(); +    } + +    @Test +    public void testTransitory_withCause() throws Exception { +        Exception cause = new IOException(); + +        AgentException exception = AgentException.transitory(cause); + +        assertThat(exception.isTransitory()).isTrue(); +        assertThat(exception.getCause()).isEqualTo(cause); +    } + +    @Test +    public void testPermanent_isNotTransitory() throws Exception { +        AgentException exception = AgentException.permanent(); + +        assertThat(exception.isTransitory()).isFalse(); +    } + +    @Test +    public void testPermanent_withCause() throws Exception { +        Exception cause = new IOException(); + +        AgentException exception = AgentException.permanent(cause); + +        assertThat(exception.isTransitory()).isFalse(); +        assertThat(exception.getCause()).isEqualTo(cause); +    } +} diff --git a/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java new file mode 100644 index 000000000000..5ea74f163bd6 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; + +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import java.io.IOException; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class BackupExceptionTest { +    @Test +    public void testConstructor_passesCause() { +        Exception cause = new IOException(); + +        Exception exception = new BackupException(cause); + +        assertThat(exception.getCause()).isEqualTo(cause); +    } +} diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index b4bc9d199cb0..fb57d68082a2 100644 --- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -155,9 +155,7 @@ import java.util.List;  import java.util.concurrent.TimeoutException;  import java.util.stream.Stream; -// TODO: When returning to RUNNING_QUEUE vs FINAL, RUNNING_QUEUE sets status = OK. Why? Verify? -// TODO: Check queue in general, behavior w/ multiple packages -// TODO: Test PM invocation +// TODO: Test agents timing out  @RunWith(FrameworkRobolectricTestRunner.class)  @Config(          manifest = Config.NONE, @@ -370,6 +368,47 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenOnePackage_cleansUpPmFiles() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        assertCleansUpFiles(mTransport, PM_PACKAGE); +    } + +    @Test +    public void testRunTask_whenTransportReturnsTransportErrorForPm_cleansUpPmFiles() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        when(transportMock.transport.performBackup( +                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt())) +                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED); +        setUpAgent(PACKAGE_1); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        assertCleansUpFiles(mTransport, PM_PACKAGE); +    } + +    @Test +    public void testRunTask_whenTransportReturnsTransportErrorForPm_resetsBackupState() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        when(transportMock.transport.performBackup( +                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt())) +                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED); +        setUpAgent(PACKAGE_1); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile()); +    } + +    @Test      public void testRunTask_whenOnePackage_updatesBookkeeping() throws Exception {          // Transport has to be initialized to not reset current token          TransportMock transportMock = setUpInitializedTransport(mTransport); @@ -418,7 +457,7 @@ public class KeyValueBackupTaskTest {      public void testRunTask_whenNonPmPackageAndNonIncremental_doesNotBackUpPm() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          setUpAgentWithData(PACKAGE_1); -        PackageManagerBackupAgent pmAgent = spy(createPmAgent()); +        BackupAgent pmAgent = spy(createPmAgent());          when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1); @@ -431,7 +470,7 @@ public class KeyValueBackupTaskTest {      public void testRunTask_whenNonPmPackageAndPmAndNonIncremental_backsUpPm() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          setUpAgentWithData(PACKAGE_1); -        PackageManagerBackupAgent pmAgent = spy(createPmAgent()); +        BackupAgent pmAgent = spy(createPmAgent());          when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));          KeyValueBackupTask task =                  createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE); @@ -445,7 +484,7 @@ public class KeyValueBackupTaskTest {      public void testRunTask_whenNonPmPackageAndIncremental_backsUpPm() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          setUpAgentWithData(PACKAGE_1); -        PackageManagerBackupAgent pmAgent = spy(createPmAgent()); +        BackupAgent pmAgent = spy(createPmAgent());          when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1); @@ -529,6 +568,35 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenPackageUnknown() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        // Not calling setUpAgent() for PACKAGE_1 +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        verify(transportMock.transport, never()) +                .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()); +        verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND); +        verify(mObserver).backupFinished(SUCCESS); +        assertBackupNotPendingFor(PACKAGE_1); +    } + +    @Test +    public void testRunTask_whenFirstPackageUnknown_callsTransportForSecondPackage() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        // Not calling setUpAgent() for PACKAGE_1 +        setUpAgentWithData(PACKAGE_2); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2); + +        runTask(task); + +        verify(transportMock.transport) +                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()); +    } + +    @Test      public void testRunTask_whenPackageNotEligibleForBackup() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          AgentMock agentMock = setUpAgentWithData(PACKAGE_1.backupNotAllowed()); @@ -545,6 +613,19 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenFirstPackageNotEligibleForBackup_callsTransportForSecondPackage() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgentsWithData(PACKAGE_1.backupNotAllowed(), PACKAGE_2); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2); + +        runTask(task); + +        verify(transportMock.transport) +                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()); +    } + +    @Test      public void testRunTask_whenPackageDoesFullBackup() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          PackageData packageData = fullBackupPackage(1); @@ -561,6 +642,20 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenFirstPackageDoesFullBackup_callsTransportForSecondPackage() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        PackageData packageData = fullBackupPackage(1); +        setUpAgentsWithData(packageData, PACKAGE_2); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData, PACKAGE_2); + +        runTask(task); + +        verify(transportMock.transport) +                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()); +    } + +    @Test      public void testRunTask_whenPackageIsStopped() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          AgentMock agentMock = setUpAgentWithData(PACKAGE_1.stopped()); @@ -575,18 +670,16 @@ public class KeyValueBackupTaskTest {      }      @Test -    public void testRunTask_whenPackageUnknown() throws Exception { +    public void testRunTask_whenFirstPackageIsStopped_callsTransportForSecondPackage() +            throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport); -        // Not calling setUpAgent() -        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); +        setUpAgentsWithData(PACKAGE_1.stopped(), PACKAGE_2); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);          runTask(task); -        verify(transportMock.transport, never()) -                .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()); -        verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND); -        verify(mObserver).backupFinished(SUCCESS); -        assertBackupNotPendingFor(PACKAGE_1); +        verify(transportMock.transport) +                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());      }      @Test @@ -629,6 +722,7 @@ public class KeyValueBackupTaskTest {          verify(mBackupManagerService).setWorkSource(null);          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);          verify(mObserver).backupFinished(BackupManager.SUCCESS); +        assertBackupPendingFor(PACKAGE_1);      }      @Test @@ -645,6 +739,7 @@ public class KeyValueBackupTaskTest {          verify(mBackupManagerService).setWorkSource(null);          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);          verify(mObserver).backupFinished(BackupManager.SUCCESS); +        assertBackupPendingFor(PACKAGE_1);      }      @Test @@ -798,7 +893,7 @@ public class KeyValueBackupTaskTest {          runTask(task); -        assertBackupNotPendingFor(PACKAGE_1); +        assertBackupPendingFor(PACKAGE_1);      }      @Test @@ -1140,6 +1235,38 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenPmAgentWritesData_callsTransportPerformBackupWithAgentData() +            throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        Path backupDataPath = createTemporaryFile(); +        when(transportMock.transport.performBackup( +                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt())) +                .then(copyBackupDataTo(backupDataPath)); +        BackupAgent pmAgent = spy(createPmAgent()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); +        agentOnBackupDo( +                pmAgent, +                (oldState, dataOutput, newState) -> { +                    writeData(dataOutput, "key1", "data1".getBytes()); +                    writeData(dataOutput, "key2", "data2".getBytes()); +                    writeState(newState, "newState".getBytes()); +                }); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        verify(transportMock.transport) +                .performBackup(argThat(packageInfo(PM_PACKAGE)), any(), anyInt()); +        try (FileInputStream inputStream = new FileInputStream(backupDataPath.toFile())) { +            BackupDataInput backupData = new BackupDataInput(inputStream.getFD()); +            assertDataHasKeyValue(backupData, "key1", "data1".getBytes()); +            assertDataHasKeyValue(backupData, "key2", "data2".getBytes()); +            assertThat(backupData.readNextHeader()).isFalse(); +        } +    } + +    @Test      public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()              throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport); @@ -1176,6 +1303,50 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenFinishBackupSucceedsForPm_cleansUp() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); +        BackupAgent pmAgent = spy(createPmAgent()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); +        agentOnBackupDo( +                pmAgent, +                (oldState, dataOutput, newState) -> { +                    writeData(dataOutput, "key", "data".getBytes()); +                    writeState(newState, "newState".getBytes()); +                }); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        assertThat(Files.readAllBytes(getStateFile(mTransport, PM_PACKAGE))) +                .isEqualTo("newState".getBytes()); +        assertCleansUpFiles(mTransport, PM_PACKAGE); +        // We don't unbind PM +        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE))); +    } + +    @Test +    public void testRunTask_whenFinishBackupSucceedsForPm_doesNotUnbindPm() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK); +        BackupAgent pmAgent = spy(createPmAgent()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); +        agentOnBackupDo( +                pmAgent, +                (oldState, dataOutput, newState) -> { +                    writeData(dataOutput, "key", "data".getBytes()); +                    writeState(newState, "newState".getBytes()); +                }); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE))); +    } + +    @Test      public void testRunTask_whenFinishBackupSucceeds_logsBackupPackageEvent() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          setUpAgentWithData(PACKAGE_1); @@ -1354,6 +1525,7 @@ public class KeyValueBackupTaskTest {      public void testRunTask_whenTransportReturnsQuotaExceeded_updatesBookkeeping()              throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgentWithData(PACKAGE_1);          when(transportMock.transport.performBackup(                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))                  .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED); @@ -1701,9 +1873,9 @@ public class KeyValueBackupTaskTest {      }      @Test -    public void testRunTask_whenPmAgentFails() throws Exception { +    public void testRunTask_whenPmAgentFails_reportsCorrectly() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport); -        PackageManagerBackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); +        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());          when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); @@ -1718,6 +1890,75 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenPmAgentFails_revertsTask() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        assertTaskReverted(transportMock, PACKAGE_1); +    } + +    @Test +    public void testRunTask_whenPmAgentFails_cleansUpFiles() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        assertCleansUpFiles(mTransport, PM_PACKAGE); +    } + +    @Test +    public void testRunTask_whenPmAgentFails_resetsBackupState() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); + +        runTask(task); + +        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile()); +    } + +    @Test +    public void testRunTask_whenMarkCancelDuringPmOnBackup_resetsBackupState() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        BackupAgent pmAgent = spy(createPmAgent()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); +        agentOnBackupDo( +                pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); + +        runTask(task); + +        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile()); +    } + +    @Test +    public void testRunTask_whenMarkCancelDuringPmOnBackup_cleansUpFiles() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        setUpAgent(PACKAGE_1); +        BackupAgent pmAgent = spy(createPmAgent()); +        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent)); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); +        agentOnBackupDo( +                pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel)); + +        runTask(task); + +        assertCleansUpFiles(mTransport, PM_PACKAGE); +    } + +    @Test      public void testRunTask_whenBackupRunning_doesNotThrow() throws Exception {          TransportMock transportMock = setUpInitializedTransport(mTransport);          when(mBackupManagerService.isBackupOperationInProgress()).thenReturn(true); @@ -1736,7 +1977,7 @@ public class KeyValueBackupTaskTest {          runTask(task); -        verify(mReporter).onReadAgentDataError(eq(PACKAGE_1.packageName), any()); +        verify(mReporter).onAgentDataError(eq(PACKAGE_1.packageName), any());      }      @Test @@ -1779,6 +2020,24 @@ public class KeyValueBackupTaskTest {      }      @Test +    public void testRunTask_whenMarkCancelDuringAgentOnBackup_cleansUpFiles() throws Exception { +        TransportMock transportMock = setUpInitializedTransport(mTransport); +        AgentMock agentMock = setUpAgent(PACKAGE_1); +        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); +        agentOnBackupDo( +                agentMock, +                (oldState, dataOutput, newState) -> { +                    writeData(dataOutput, "key", "data".getBytes()); +                    writeState(newState, "newState".getBytes()); +                    runInWorkerThread(task::markCancel); +                }); + +        runTask(task); + +        assertCleansUpFiles(mTransport, PACKAGE_1); +    } + +    @Test      public void              testRunTask_whenMarkCancelDuringFirstAgentOnBackup_doesNotCallTransportAfterWaitCancel()                      throws Exception { @@ -2293,20 +2552,28 @@ public class KeyValueBackupTaskTest {       */      private static void agentOnBackupDo(AgentMock agentMock, BackupAgentOnBackup function)              throws Exception { -        doAnswer( -                        (BackupAgentOnBackup) -                                (oldState, dataOutput, newState) -> { -                                    ByteArrayOutputStream outputStream = -                                            new ByteArrayOutputStream(); -                                    transferStreamedData( -                                            new FileInputStream(oldState.getFileDescriptor()), -                                            outputStream); -                                    agentMock.oldState = outputStream.toByteArray(); -                                    agentMock.oldStateHistory.add(agentMock.oldState); -                                    function.onBackup(oldState, dataOutput, newState); -                                }) -                .when(agentMock.agent) -                .onBackup(any(), any(), any()); +        agentOnBackupDo( +                agentMock.agent, +                (oldState, dataOutput, newState) -> { +                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); +                    transferStreamedData( +                            new FileInputStream(oldState.getFileDescriptor()), outputStream); +                    agentMock.oldState = outputStream.toByteArray(); +                    agentMock.oldStateHistory.add(agentMock.oldState); +                    function.onBackup(oldState, dataOutput, newState); +                }); +    } + +    /** +     * Implements {@code function} for {@link BackupAgent#onBackup(ParcelFileDescriptor, +     * BackupDataOutput, ParcelFileDescriptor)} of {@code agentMock}. +     * +     * @see #agentOnBackupDo(AgentMock, BackupAgentOnBackup) +     * @see #remoteAgentOnBackupThrows(AgentMock, BackupAgentOnBackup) +     */ +    private static void agentOnBackupDo(BackupAgent backupAgent, BackupAgentOnBackup function) +            throws IOException { +        doAnswer(function).when(backupAgent).onBackup(any(), any(), any());      }      /** @@ -2400,6 +2667,10 @@ public class KeyValueBackupTaskTest {              // constructor              assertJournalDoesNotContain(mBackupManagerService.getJournal(), packageName);              assertThat(mBackupManagerService.getPendingBackups()).doesNotContainKey(packageName); +            // Also verifying BMS is never called since for some cases the package wouldn't be +            // pending for other reasons (for example it's not eligible for backup). Regardless of +            // these reasons, we shouldn't mark them as pending backup (call dataChangedImpl()). +            verify(mBackupManagerService, never()).dataChangedImpl(packageName);          }      } diff --git a/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java new file mode 100644 index 000000000000..4b79657b1dae --- /dev/null +++ b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.keyvalue; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.expectThrows; + +import android.app.backup.BackupTransport; +import android.platform.test.annotations.Presubmit; + +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import java.io.IOException; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class TaskExceptionTest { +    @Test +    public void testStateCompromised() { +        TaskException exception = TaskException.stateCompromised(); + +        assertThat(exception.isStateCompromised()).isTrue(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR); +    } + +    @Test +    public void testStateCompromised_whenCauseInstanceOfTaskException() { +        Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED); + +        TaskException exception = TaskException.stateCompromised(cause); + +        assertThat(exception.isStateCompromised()).isTrue(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED); +        assertThat(exception.getCause()).isEqualTo(cause); +    } + +    @Test +    public void testStateCompromised_whenCauseNotInstanceOfTaskException() { +        Exception cause = new IOException(); + +        TaskException exception = TaskException.stateCompromised(cause); + +        assertThat(exception.isStateCompromised()).isTrue(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR); +        assertThat(exception.getCause()).isEqualTo(cause); +    } + +    @Test +    public void testForStatus_whenTransportOk_throws() { +        expectThrows( +                IllegalArgumentException.class, +                () -> TaskException.forStatus(BackupTransport.TRANSPORT_OK)); +    } + +    @Test +    public void testForStatus_whenTransportNotInitialized() { +        TaskException exception = +                TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED); + +        assertThat(exception.isStateCompromised()).isFalse(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED); +    } + +    @Test +    public void testCausedBy_whenCauseInstanceOfTaskException_returnsCause() { +        Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED); + +        TaskException exception = TaskException.causedBy(cause); + +        assertThat(exception).isEqualTo(cause); +    } + +    @Test +    public void testCausedBy_whenCauseNotInstanceOfTaskException() { +        Exception cause = new IOException(); + +        TaskException exception = TaskException.causedBy(cause); + +        assertThat(exception).isNotEqualTo(cause); +        assertThat(exception.isStateCompromised()).isFalse(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR); +        assertThat(exception.getCause()).isEqualTo(cause); +    } + +    @Test +    public void testCreate() { +        TaskException exception = TaskException.create(); + +        assertThat(exception.isStateCompromised()).isFalse(); +        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR); +    } + +    @Test +    public void testIsStateCompromised_whenStateCompromised_returnsTrue() { +        TaskException taskException = TaskException.stateCompromised(); + +        boolean stateCompromised = taskException.isStateCompromised(); + +        assertThat(stateCompromised).isTrue(); +    } + +    @Test +    public void testIsStateCompromised_whenCreatedWithCreate_returnsFalse() { +        TaskException taskException = TaskException.create(); + +        boolean stateCompromised = taskException.isStateCompromised(); + +        assertThat(stateCompromised).isFalse(); +    } + +    @Test +    public void testGetStatus_whenStatusIsTransportPackageRejected() { +        TaskException taskException = +                TaskException.forStatus(BackupTransport.TRANSPORT_PACKAGE_REJECTED); + +        int status = taskException.getStatus(); + +        assertThat(status).isEqualTo(BackupTransport.TRANSPORT_PACKAGE_REJECTED); +    } + +    @Test +    public void testGetStatus_whenStatusIsTransportNotInitialized() { +        TaskException taskException = +                TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED); + +        int status = taskException.getStatus(); + +        assertThat(status).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED); +    } +} diff --git a/services/robotests/src/com/android/server/backup/testing/TransportData.java b/services/robotests/src/com/android/server/backup/testing/TransportData.java index 4c67180050e2..77f5d9a48c18 100644 --- a/services/robotests/src/com/android/server/backup/testing/TransportData.java +++ b/services/robotests/src/com/android/server/backup/testing/TransportData.java @@ -48,9 +48,9 @@ public class TransportData {      public static TransportData localTransport() {          return new TransportData( -                "android/com.android.internal.backup.LocalTransport", -                "android/com.android.internal.backup.LocalTransportService", -                "com.android.internal.backup.LocalTransport", +                "com.android.localtransport/.LocalTransport", +                "com.android.localtransport/.LocalTransportService", +                "com.android.localtransport.LocalTransport",                  null,                  "Backing up to debug-only private cache",                  null, diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java index 06c74371eb51..9a283febe906 100644 --- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java @@ -16,9 +16,13 @@  package com.android.server.am; +import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;  import static com.android.server.am.MemoryStatUtil.MemoryStat; +import static com.android.server.am.MemoryStatUtil.PAGE_SIZE; +import static com.android.server.am.MemoryStatUtil.parseMemoryMaxUsageFromMemCg;  import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;  import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs; +import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;  import static org.junit.Assert.assertEquals;  import static org.junit.Assert.assertNull; @@ -29,10 +33,12 @@ import androidx.test.runner.AndroidJUnit4;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.util.Collections; +  @RunWith(AndroidJUnit4.class)  @SmallTest  public class MemoryStatUtilTest { -    private String MEMORY_STAT_CONTENTS = String.join( +    private static final String MEMORY_STAT_CONTENTS = String.join(              "\n",              "cache 96", // keep different from total_cache to catch reading wrong value              "rss 97", // keep different from total_rss to catch reading wrong value @@ -67,7 +73,7 @@ public class MemoryStatUtilTest {              "total_active_file 81920",              "total_unevictable 0"); -    private String PROC_STAT_CONTENTS = String.join( +    private static final String PROC_STAT_CONTENTS = String.join(              " ",              "1040",              "(system_server)", @@ -92,7 +98,7 @@ public class MemoryStatUtilTest {              "0",              "2206",              "1257177088", -            "3", // this is rss in bytes +            "3", // this is RSS (number of pages)              "4294967295",              "2936971264",              "2936991289", @@ -122,18 +128,65 @@ public class MemoryStatUtilTest {              "3198889956",              "0"); +    private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n" +        + "State:\tS (sleeping)\n" +        + "Tgid:\t12088\n" +        + "Pid:\t12088\n" +        + "PPid:\t723\n" +        + "TracerPid:\t0\n" +        + "Uid:\t10083\t10083\t10083\t10083\n" +        + "Gid:\t10083\t10083\t10083\t10083\n" +        + "Ngid:\t0\n" +        + "FDSize:\t128\n" +        + "Groups:\t3003 9997 20083 50083 \n" +        + "VmPeak:\t 4546844 kB\n" +        + "VmSize:\t 4542636 kB\n" +        + "VmLck:\t       0 kB\n" +        + "VmPin:\t       0 kB\n" +        + "VmHWM:\t  137668 kB\n" // RSS high watermark +        + "VmRSS:\t  126776 kB\n" +        + "RssAnon:\t   37860 kB\n" +        + "RssFile:\t   88764 kB\n" +        + "RssShmem:\t     152 kB\n" +        + "VmData:\t 4125112 kB\n" +        + "VmStk:\t    8192 kB\n" +        + "VmExe:\t      24 kB\n" +        + "VmLib:\t  102432 kB\n" +        + "VmPTE:\t    1300 kB\n" +        + "VmPMD:\t      36 kB\n" +        + "VmSwap:\t       0 kB\n" +        + "Threads:\t95\n" +        + "SigQ:\t0/13641\n" +        + "SigPnd:\t0000000000000000\n" +        + "ShdPnd:\t0000000000000000\n" +        + "SigBlk:\t0000000000001204\n" +        + "SigIgn:\t0000000000000001\n" +        + "SigCgt:\t00000006400084f8\n" +        + "CapInh:\t0000000000000000\n" +        + "CapPrm:\t0000000000000000\n" +        + "CapEff:\t0000000000000000\n" +        + "CapBnd:\t0000000000000000\n" +        + "CapAmb:\t0000000000000000\n" +        + "Seccomp:\t2\n" +        + "Cpus_allowed:\tff\n" +        + "Cpus_allowed_list:\t0-7\n" +        + "Mems_allowed:\t1\n" +        + "Mems_allowed_list:\t0\n" +        + "voluntary_ctxt_switches:\t903\n" +        + "nonvoluntary_ctxt_switches:\t104\n"; +      @Test -    public void testParseMemoryStatFromMemcg_parsesCorrectValues() throws Exception { +    public void testParseMemoryStatFromMemcg_parsesCorrectValues() {          MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS); -        assertEquals(stat.pgfault, 1); -        assertEquals(stat.pgmajfault, 2); -        assertEquals(stat.rssInBytes, 3); -        assertEquals(stat.cacheInBytes, 4); -        assertEquals(stat.swapInBytes, 5); +        assertEquals(1, stat.pgfault); +        assertEquals(2, stat.pgmajfault); +        assertEquals(3, stat.rssInBytes); +        assertEquals(4, stat.cacheInBytes); +        assertEquals(5, stat.swapInBytes);      }      @Test -    public void testParseMemoryStatFromMemcg_emptyMemoryStatContents() throws Exception { +    public void testParseMemoryStatFromMemcg_emptyMemoryStatContents() {          MemoryStat stat = parseMemoryStatFromMemcg("");          assertNull(stat); @@ -142,21 +195,56 @@ public class MemoryStatUtilTest {      }      @Test -    public void testParseMemoryStatFromProcfs_parsesCorrectValues() throws Exception { +    public void testParseMemoryMaxUsageFromMemCg_parsesCorrectValue() { +        assertEquals(1234, parseMemoryMaxUsageFromMemCg("1234")); +    } + +    @Test +    public void testParseMemoryMaxUsageFromMemCg_emptyContents() { +        assertEquals(0, parseMemoryMaxUsageFromMemCg("")); + +        assertEquals(0, parseMemoryMaxUsageFromMemCg(null)); +    } + +    @Test +    public void testParseMemoryMaxUsageFromMemCg_incorrectValue() { +        assertEquals(0, parseMemoryMaxUsageFromMemCg("memory")); +    } + +    @Test +    public void testParseMemoryStatFromProcfs_parsesCorrectValues() {          MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS);          assertEquals(1, stat.pgfault);          assertEquals(2, stat.pgmajfault); -        assertEquals(3, stat.rssInBytes); +        assertEquals(3 * PAGE_SIZE, stat.rssInBytes);          assertEquals(0, stat.cacheInBytes);          assertEquals(0, stat.swapInBytes);      }      @Test -    public void testParseMemoryStatFromProcfs_emptyContents() throws Exception { +    public void testParseMemoryStatFromProcfs_emptyContents() {          MemoryStat stat = parseMemoryStatFromProcfs("");          assertNull(stat);          stat = parseMemoryStatFromProcfs(null);          assertNull(stat);      } + +    @Test +    public void testParseMemoryStatFromProcfs_invalidValue() { +        String contents = String.join(" ", Collections.nCopies(24, "memory")); +        assertNull(parseMemoryStatFromProcfs(contents)); +    } + +    @Test +    public void testParseVmHWMFromProcfs_parsesCorrectValue() { +        assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS) / BYTES_IN_KILOBYTE); +    } + +    @Test +    public void testParseVmHWMFromProcfs_emptyContents() { +        assertEquals(0, parseVmHWMFromProcfs("")); + +        assertEquals(0, parseVmHWMFromProcfs(null)); +    }  } diff --git a/services/tests/servicestests/src/com/android/server/am/PersistentConnectionTest.java b/services/tests/servicestests/src/com/android/server/am/PersistentConnectionTest.java index 54f93a88a387..39cab8d2888a 100644 --- a/services/tests/servicestests/src/com/android/server/am/PersistentConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/am/PersistentConnectionTest.java @@ -56,6 +56,11 @@ public class PersistentConnectionTest extends AndroidTestCase {          }          @Override +        protected int getBindFlags() { +            return Context.BIND_FOREGROUND_SERVICE; +        } + +        @Override          protected IDeviceAdminService asInterface(IBinder binder) {              return (IDeviceAdminService) binder;          } diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java new file mode 100644 index 000000000000..5a787ec1cff3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.server.usage; + +import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.fail; + +import static org.testng.Assert.assertEquals; + +import android.app.usage.EventList; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.res.Configuration; +import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UsageStatsDatabaseTest { +    protected Context mContext; +    private UsageStatsDatabase mUsageStatsDatabase; +    private File mTestDir; + +    private IntervalStats mIntervalStats = new IntervalStats(); +    private long mEndTime = 0; + +    private static final UsageStatsDatabase.StatCombiner<IntervalStats> mIntervalStatsVerifier = +            new UsageStatsDatabase.StatCombiner<IntervalStats>() { +                @Override +                public void combine(IntervalStats stats, boolean mutable, +                        List<IntervalStats> accResult) { +                    accResult.add(stats); +                } +            }; + +    @Before +    public void setUp() { +        mContext = InstrumentationRegistry.getTargetContext(); +        mTestDir = new File(mContext.getFilesDir(), "UsageStatsDatabaseTest"); +        mUsageStatsDatabase = new UsageStatsDatabase(mTestDir); +        mUsageStatsDatabase.init(1); +        populateIntervalStats(); +        clearUsageStatsFiles(); +    } + +    /** +     * A debugging utility for viewing the files currently in the test directory +     */ +    private void clearUsageStatsFiles() { +        File[] intervalDirs = mTestDir.listFiles(); +        for (File intervalDir : intervalDirs) { +            if (intervalDir.isDirectory()) { +                File[] usageFiles = intervalDir.listFiles(); +                for (File f : usageFiles) { +                    f.delete(); +                } +            } +        } +    } + +    /** +     * A debugging utility for viewing the files currently in the test directory +     */ +    private String dumpUsageStatsFiles() { +        StringBuilder sb = new StringBuilder(); +        File[] intervalDirs = mTestDir.listFiles(); +        for (File intervalDir : intervalDirs) { +            if (intervalDir.isDirectory()) { +                File[] usageFiles = intervalDir.listFiles(); +                for (File f : usageFiles) { +                    sb.append(f.toString()); +                } +            } +        } +        return sb.toString(); +    } + +    private void populateIntervalStats() { +        final int numberOfEvents = 3000; +        long time = 1; +        mIntervalStats = new IntervalStats(); + +        mIntervalStats.beginTime = 1; +        mIntervalStats.interactiveTracker.count = 2; +        mIntervalStats.interactiveTracker.duration = 111111; +        mIntervalStats.nonInteractiveTracker.count = 3; +        mIntervalStats.nonInteractiveTracker.duration = 222222; +        mIntervalStats.keyguardShownTracker.count = 4; +        mIntervalStats.keyguardShownTracker.duration = 333333; +        mIntervalStats.keyguardHiddenTracker.count = 5; +        mIntervalStats.keyguardHiddenTracker.duration = 4444444; + +        if (mIntervalStats.events == null) { +            mIntervalStats.events = new EventList(); +        } + +        for (int i = 0; i < numberOfEvents; i++) { +            UsageEvents.Event event = new UsageEvents.Event(); +            final int packageInt = ((i / 3) % 7); +            event.mPackage = "fake.package.name" + packageInt; //clusters of 3 events from 7 "apps" +            if (packageInt == 3) { +                // Third app is an instant app +                event.mFlags |= UsageEvents.Event.FLAG_IS_PACKAGE_INSTANT_APP; +            } else if (packageInt == 2 || packageInt == 4) { +                event.mClass = ".fake.class.name" + i % 11; +            } + + +            event.mTimeStamp = time; +            event.mEventType = i % 19; //"random" event type + +            switch (event.mEventType) { +                case UsageEvents.Event.CONFIGURATION_CHANGE: +                    //empty config, +                    event.mConfiguration = new Configuration(); +                    break; +                case UsageEvents.Event.SHORTCUT_INVOCATION: +                    //"random" shortcut +                    event.mShortcutId = "shortcut" + (i % 8); +                    break; +                case UsageEvents.Event.STANDBY_BUCKET_CHANGED: +                    //"random" bucket and reason +                    event.mBucketAndReason = (((i % 5 + 1) * 10) << 16) & (i % 5 + 1) << 8; +                    break; +                case UsageEvents.Event.NOTIFICATION_INTERRUPTION: +                    //"random" channel +                    event.mNotificationChannelId = "channel" + (i % 5); +                    break; +            } + +            mIntervalStats.events.insert(event); +            mIntervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType); + +            time += 23; // Arbitrary progression of time +        } +        mEndTime = time; + +        Configuration config1 = new Configuration(); +        config1.fontScale = 3.3f; +        config1.mcc = 4; +        mIntervalStats.getOrCreateConfigurationStats(config1); + +        Configuration config2 = new Configuration(); +        config2.mnc = 5; +        config2.setLocale(new Locale("en", "US")); +        mIntervalStats.getOrCreateConfigurationStats(config2); + +        Configuration config3 = new Configuration(); +        config3.touchscreen = 6; +        config3.keyboard = 7; +        mIntervalStats.getOrCreateConfigurationStats(config3); + +        Configuration config4 = new Configuration(); +        config4.keyboardHidden = 8; +        config4.hardKeyboardHidden = 9; +        mIntervalStats.getOrCreateConfigurationStats(config4); + +        Configuration config5 = new Configuration(); +        config5.navigation = 10; +        config5.navigationHidden = 11; +        mIntervalStats.getOrCreateConfigurationStats(config5); + +        Configuration config6 = new Configuration(); +        config6.orientation = 12; +        //Ignore screen layout, it's determined by locale +        mIntervalStats.getOrCreateConfigurationStats(config6); + +        Configuration config7 = new Configuration(); +        config7.colorMode = 14; +        config7.uiMode = 15; +        mIntervalStats.getOrCreateConfigurationStats(config7); + +        Configuration config8 = new Configuration(); +        config8.screenWidthDp = 16; +        config8.screenHeightDp = 17; +        mIntervalStats.getOrCreateConfigurationStats(config8); + +        Configuration config9 = new Configuration(); +        config9.smallestScreenWidthDp = 18; +        config9.densityDpi = 19; +        mIntervalStats.getOrCreateConfigurationStats(config9); + +        mIntervalStats.activeConfiguration = config9; +    } + +    void compareUsageStats(UsageStats us1, UsageStats us2) { +        assertEquals(us1.mPackageName, us2.mPackageName); +        // mBeginTimeStamp is based on the enclosing IntervalStats, don't bother checking +        // mEndTimeStamp is based on the enclosing IntervalStats, don't bother checking +        assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed); +        assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground); +        // mLaunchCount not persisted, so skipped +        assertEquals(us1.mAppLaunchCount, us2.mAppLaunchCount); +        assertEquals(us1.mLastEvent, us2.mLastEvent); +        assertEquals(us1.mChooserCounts, us2.mChooserCounts); +    } + +    void compareUsageEvent(UsageEvents.Event e1, UsageEvents.Event e2, int debugId) { +        assertEquals(e1.mPackage, e2.mPackage, "Usage event " + debugId); +        assertEquals(e1.mClass, e2.mClass, "Usage event " + debugId); +        assertEquals(e1.mTimeStamp, e2.mTimeStamp, "Usage event " + debugId); +        assertEquals(e1.mEventType, e2.mEventType, "Usage event " + debugId); +        switch (e1.mEventType) { +            case UsageEvents.Event.CONFIGURATION_CHANGE: +                assertEquals(e1.mConfiguration, e2.mConfiguration, +                        "Usage event " + debugId + e2.mConfiguration.toString()); +                break; +            case UsageEvents.Event.SHORTCUT_INVOCATION: +                assertEquals(e1.mShortcutId, e2.mShortcutId, "Usage event " + debugId); +                break; +            case UsageEvents.Event.STANDBY_BUCKET_CHANGED: +                assertEquals(e1.mBucketAndReason, e2.mBucketAndReason, "Usage event " + debugId); +                break; +            case UsageEvents.Event.NOTIFICATION_INTERRUPTION: +                assertEquals(e1.mNotificationChannelId, e2.mNotificationChannelId, +                        "Usage event " + debugId); +                break; +        } +        assertEquals(e1.mFlags, e2.mFlags); +    } + +    void compareIntervalStats(IntervalStats stats1, IntervalStats stats2) { +        assertEquals(stats1.beginTime, stats2.beginTime); +        assertEquals(stats1.endTime, stats2.endTime); +        assertEquals(stats1.interactiveTracker.count, stats2.interactiveTracker.count); +        assertEquals(stats1.interactiveTracker.duration, stats2.interactiveTracker.duration); +        assertEquals(stats1.nonInteractiveTracker.count, stats2.nonInteractiveTracker.count); +        assertEquals(stats1.nonInteractiveTracker.duration, stats2.nonInteractiveTracker.duration); +        assertEquals(stats1.keyguardShownTracker.count, stats2.keyguardShownTracker.count); +        assertEquals(stats1.keyguardShownTracker.duration, stats2.keyguardShownTracker.duration); +        assertEquals(stats1.keyguardHiddenTracker.count, stats2.keyguardHiddenTracker.count); +        assertEquals(stats1.keyguardHiddenTracker.duration, stats2.keyguardHiddenTracker.duration); + +        String[] usageKey1 = stats1.packageStats.keySet().toArray(new String[0]); +        String[] usageKey2 = stats2.packageStats.keySet().toArray(new String[0]); +        for (int i = 0; i < usageKey1.length; i++) { +            UsageStats usageStats1 = stats1.packageStats.get(usageKey1[i]); +            UsageStats usageStats2 = stats2.packageStats.get(usageKey2[i]); +            compareUsageStats(usageStats1, usageStats2); +        } + +        assertEquals(stats1.configurations.size(), stats2.configurations.size()); +        Configuration[] configSet1 = stats1.configurations.keySet().toArray(new Configuration[0]); +        for (int i = 0; i < configSet1.length; i++) { +            if (!stats2.configurations.containsKey(configSet1[i])) { +                Configuration[] configSet2 = stats2.configurations.keySet().toArray( +                        new Configuration[0]); +                String debugInfo = ""; +                for (Configuration c : configSet1) { +                    debugInfo += c.toString() + "\n"; +                } +                debugInfo += "\n"; +                for (Configuration c : configSet2) { +                    debugInfo += c.toString() + "\n"; +                } +                fail("Config " + configSet1[i].toString() +                        + " not found in deserialized IntervalStat\n" + debugInfo); +            } +        } +        assertEquals(stats1.activeConfiguration, stats2.activeConfiguration); + +        assertEquals(stats1.events.size(), stats2.events.size()); +        for (int i = 0; i < stats1.events.size(); i++) { +            compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i); +        } +    } + +    /** +     * Runs the Write Read test. +     * Will write the generated IntervalStat to disk, read it from disk and compare the two +     */ +    void runWriteReadTest(int interval) throws IOException { +        mUsageStatsDatabase.putUsageStats(interval, mIntervalStats); +        List<IntervalStats> stats = mUsageStatsDatabase.queryUsageStats(interval, 0, mEndTime, +                mIntervalStatsVerifier); + +        assertEquals(1, stats.size()); +        compareIntervalStats(mIntervalStats, stats.get(0)); +    } + +    /** +     * Demonstrate that IntervalStats can be serialized and deserialized from disk without loss of +     * relevant data. +     */ +    @Test +    public void testWriteRead() throws IOException { +        runWriteReadTest(UsageStatsManager.INTERVAL_DAILY); +        runWriteReadTest(UsageStatsManager.INTERVAL_WEEKLY); +        runWriteReadTest(UsageStatsManager.INTERVAL_MONTHLY); +        runWriteReadTest(UsageStatsManager.INTERVAL_YEARLY); +    } + +    /** +     * Runs the Version Change tests. +     * Will write the generated IntervalStat to disk in one version format, "upgrade" to another +     * version and read the automatically upgraded files on disk in the new file format. +     */ +    void runVersionChangeTest(int oldVersion, int newVersion, int interval) throws IOException { +        // Write IntervalStats to disk in old version format +        UsageStatsDatabase prevDB = new UsageStatsDatabase(mTestDir, oldVersion); +        prevDB.init(1); +        prevDB.putUsageStats(interval, mIntervalStats); + +        // Simulate an upgrade to a new version and read from the disk +        UsageStatsDatabase newDB = new UsageStatsDatabase(mTestDir, newVersion); +        newDB.init(mEndTime); +        List<IntervalStats> stats = newDB.queryUsageStats(interval, 0, mEndTime, +                mIntervalStatsVerifier); + +        assertEquals(1, stats.size()); +        // The written and read IntervalStats should match +        compareIntervalStats(mIntervalStats, stats.get(0)); +    } + +    /** +     * Test the version upgrade from 3 to 4 +     */ +    @Test +    public void testVersionUpgradeFrom3to4() throws IOException { +        runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_DAILY); +        runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_WEEKLY); +        runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_MONTHLY); +        runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_YEARLY); +    } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java index e7c45d59078c..088e22972cc9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -16,6 +16,7 @@  package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;  import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;  import static android.view.Display.DEFAULT_DISPLAY; @@ -24,6 +25,8 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P  import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;  import static org.junit.Assert.fail; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.atLeast;  import static org.mockito.Mockito.verify; @@ -33,9 +36,11 @@ import static org.mockito.Mockito.when;  import android.os.Binder;  import android.os.IInterface;  import android.platform.test.annotations.Presubmit; +import android.util.SparseBooleanArray;  import android.view.IRecentsAnimationRunner;  import android.view.SurfaceControl; +import androidx.test.filters.FlakyTest;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; @@ -109,6 +114,25 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {          }      } +    @Test +    @FlakyTest(bugId = 117117823) +    public void testIncludedApps_expectTargetAndVisible() throws Exception { +        sWm.setRecentsAnimationController(mController); +        final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent, +                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); +        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent, +                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); +        final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent, +                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); +        hiddenAppWindow.setHidden(true); +        mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray()); + +        // Ensure that we are animating the target activity as well +        assertTrue(mController.isAnimatingTask(homeAppWindow.getTask())); +        assertTrue(mController.isAnimatingTask(appWindow.getTask())); +        assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask())); +    } +      private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {          verify(binder, atLeast(0)).asBinder();          verifyNoMoreInteractions(binder); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index 6af3ea763c13..b7cc9ce7a619 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -76,7 +76,8 @@ import androidx.test.runner.AndroidJUnit4;   */  @SmallTest  @FlakyTest(bugId = 74078662) -@Presubmit +// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed. +// @Presubmit  @RunWith(AndroidJUnit4.class)  public class WindowStateTests extends WindowTestsBase { @@ -369,22 +370,31 @@ public class WindowStateTests extends WindowTestsBase {          final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);          app.mHasSurface = true; -        app.mToken.mSurfaceControl = mock(SurfaceControl.class); +        app.mSurfaceControl = mock(SurfaceControl.class);          try {              app.getFrameLw().set(10, 20, 60, 80); +            app.updateSurfacePosition(t);              app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);              assertTrue(app.mSeamlesslyRotated); + +            // Verify we un-rotate the window state surface.              Matrix matrix = new Matrix();              // Un-rotate 90 deg              matrix.setRotate(270);              // Translate it back to origin              matrix.postTranslate(0, mDisplayInfo.logicalWidth); -            verify(t).setMatrix(eq(app.mToken.mSurfaceControl), eq(matrix), any(float[].class)); +            verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class)); + +            // Verify we update the position as well. +            float[] currentSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y}; +            matrix.mapPoints(currentSurfacePos); +            verify(t).setPosition(eq(app.mSurfaceControl), eq(currentSurfacePos[0]), +                    eq(currentSurfacePos[1]));          } finally { +            app.mSurfaceControl = null;              app.mHasSurface = false; -            app.mToken.mSurfaceControl = null;          }      } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java index bbc6550d5753..01b7c4f650e7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java @@ -59,7 +59,8 @@ import java.nio.charset.StandardCharsets;   */  @SmallTest  @FlakyTest(bugId = 74078662) -@Presubmit +// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed. +// @Presubmit  @RunWith(AndroidJUnit4.class)  public class WindowTracingTest extends WindowTestsBase { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 45d2fa2d16a4..58aae2b12c21 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2192,6 +2192,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {      }      @Test +    public void testDontAutogroupIfCritical() throws Exception { +        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); +        r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW); +        mService.addEnqueuedNotification(r); +        NotificationManagerService.PostNotificationRunnable runnable = +                mService.new PostNotificationRunnable(r.getKey()); +        runnable.run(); + +        r = generateNotificationRecord(mTestNotificationChannel, 1, null, false); +        r.setCriticality(CriticalNotificationExtractor.CRITICAL); +        runnable = mService.new PostNotificationRunnable(r.getKey()); +        mService.addEnqueuedNotification(r); + +        runnable.run(); +        waitForIdle(); + +        verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); +    } + +    @Test      public void testNoFakeColorizedPermission() throws Exception {          when(mPackageManagerClient.checkPermission(any(), any())).thenReturn(PERMISSION_DENIED);          Notification.Builder nb = new Notification.Builder(mContext, @@ -3428,17 +3448,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {      }      @Test -    public void testResolveNotificationUid_sameAppWrongPkg() throws Exception { +    public void testResolveNotificationUid_sameAppDiffPackage() throws Exception {          ApplicationInfo info = new ApplicationInfo();          info.uid = Binder.getCallingUid(); -        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info); +        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info); -        try { -            mService.resolveNotificationUid("caller", "other", info.uid, 0); -            fail("Incorrect pkg didn't throw security exception"); -        } catch (SecurityException e) { -            // yay -        } +        int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0); + +        assertEquals(info.uid, actualUid);      }      @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 702161e48b75..13f3e5e7a3ad 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -1030,6 +1030,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {          assertEquals(1, mZenModeHelperSpy.mConditions.mSubscriptions.size());      } +    @Test +    public void testEmptyDefaultRulesMap() { +        ZenModeConfig config = new ZenModeConfig(); +        config.automaticRules = new ArrayMap<>(); +        mZenModeHelperSpy.mConfig = config; +        mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer +    } +      private void setupZenConfig() {          mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;          mZenModeHelperSpy.mConfig.allowAlarms = false; diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 4b7e21f2d536..db9972f96b21 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -24,7 +24,9 @@ import android.app.usage.UsageStats;  import android.content.res.Configuration;  import android.util.ArrayMap;  import android.util.ArraySet; +import android.util.proto.ProtoInputStream; +import java.io.IOException;  import java.util.List;  import com.android.internal.annotations.VisibleForTesting; @@ -46,7 +48,7 @@ public class IntervalStats {      // keep hundreds of strings that have the same contents. We will read the string      // and only keep it if it's not in the cache. The GC will take care of the      // strings that had identical copies in the cache. -    private final ArraySet<String> mStringCache = new ArraySet<>(); +    public final ArraySet<String> mStringCache = new ArraySet<>();      public static final class EventTracker {          public long curStartTime; @@ -129,6 +131,90 @@ public class IntervalStats {          return event;      } +    /** +     * Builds a UsageEvents.Event from a proto, but does not add it internally. +     * Built here to take advantage of the cached String Refs +     */ +    UsageEvents.Event buildEvent(ProtoInputStream parser, List<String> stringPool) +            throws IOException { +        final UsageEvents.Event event = new UsageEvents.Event(); +        while (true) { +            switch (parser.nextField()) { +                case (int) IntervalStatsProto.Event.PACKAGE: +                    event.mPackage = getCachedStringRef( +                            parser.readString(IntervalStatsProto.Event.PACKAGE)); +                    break; +                case (int) IntervalStatsProto.Event.PACKAGE_INDEX: +                    event.mPackage = getCachedStringRef(stringPool.get( +                            parser.readInt(IntervalStatsProto.Event.PACKAGE_INDEX) - 1)); +                    break; +                case (int) IntervalStatsProto.Event.CLASS: +                    event.mClass = getCachedStringRef( +                            parser.readString(IntervalStatsProto.Event.CLASS)); +                    break; +                case (int) IntervalStatsProto.Event.CLASS_INDEX: +                    event.mClass = getCachedStringRef(stringPool.get( +                            parser.readInt(IntervalStatsProto.Event.CLASS_INDEX) - 1)); +                    break; +                case (int) IntervalStatsProto.Event.TIME_MS: +                    event.mTimeStamp = beginTime + parser.readLong( +                            IntervalStatsProto.Event.TIME_MS); +                    break; +                case (int) IntervalStatsProto.Event.FLAGS: +                    event.mFlags = parser.readInt(IntervalStatsProto.Event.FLAGS); +                    break; +                case (int) IntervalStatsProto.Event.TYPE: +                    event.mEventType = parser.readInt(IntervalStatsProto.Event.TYPE); +                    break; +                case (int) IntervalStatsProto.Event.CONFIG: +                    event.mConfiguration = new Configuration(); +                    event.mConfiguration.readFromProto(parser, IntervalStatsProto.Event.CONFIG); +                    break; +                case (int) IntervalStatsProto.Event.SHORTCUT_ID: +                    event.mShortcutId = parser.readString( +                            IntervalStatsProto.Event.SHORTCUT_ID).intern(); +                    break; +                case (int) IntervalStatsProto.Event.STANDBY_BUCKET: +                    event.mBucketAndReason = parser.readInt( +                            IntervalStatsProto.Event.STANDBY_BUCKET); +                    break; +                case (int) IntervalStatsProto.Event.NOTIFICATION_CHANNEL: +                    event.mNotificationChannelId = parser.readString( +                            IntervalStatsProto.Event.NOTIFICATION_CHANNEL); +                    break; +                case (int) IntervalStatsProto.Event.NOTIFICATION_CHANNEL_INDEX: +                    event.mNotificationChannelId = getCachedStringRef(stringPool.get( +                            parser.readInt(IntervalStatsProto.Event.NOTIFICATION_CHANNEL_INDEX) +                                    - 1)); +                    break; +                case ProtoInputStream.NO_MORE_FIELDS: +                    // Handle default values for certain events types +                    switch (event.mEventType) { +                        case UsageEvents.Event.CONFIGURATION_CHANGE: +                            if (event.mConfiguration == null) { +                                event.mConfiguration = new Configuration(); +                            } +                            break; +                        case UsageEvents.Event.SHORTCUT_INVOCATION: +                            if (event.mShortcutId == null) { +                                event.mShortcutId = ""; +                            } +                            break; +                        case UsageEvents.Event.NOTIFICATION_INTERRUPTION: +                            if (event.mNotificationChannelId == null) { +                                event.mNotificationChannelId = ""; +                            } +                            break; +                    } +                    if (event.mTimeStamp == 0) { +                        //mTimestamp not set, assume default value 0 plus beginTime +                        event.mTimeStamp = beginTime; +                    } +                    return event; +            } +        } +    } +      private boolean isStatefulEvent(int eventType) {          switch (eventType) {              case UsageEvents.Event.MOVE_TO_FOREGROUND: @@ -143,8 +229,6 @@ public class IntervalStats {      /**       * Returns whether the event type is one caused by user visible       * interaction. Excludes those that are internally generated. -     * @param eventType -     * @return       */      private boolean isUserVisibleEvent(int eventType) {          return eventType != UsageEvents.Event.SYSTEM_INTERACTION @@ -184,6 +268,25 @@ public class IntervalStats {          endTime = timeStamp;      } +    /** +     * @hide +     */ +    @VisibleForTesting +    public void addEvent(UsageEvents.Event event) { +        if (events == null) { +            events = new EventList(); +        } +        // Cache common use strings +        event.mPackage = getCachedStringRef(event.mPackage); +        if (event.mClass != null) { +            event.mClass = getCachedStringRef(event.mClass); +        } +        if (event.mEventType == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { +            event.mNotificationChannelId = getCachedStringRef(event.mNotificationChannelId); +        } +        events.insert(event); +    } +      void updateChooserCounts(String packageName, String category, String action) {          UsageStats usageStats = getOrCreateUsageStats(packageName);          if (usageStats.mChooserCounts == null) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index 5ab5dc223d9e..c616685ba302 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -17,6 +17,7 @@  package com.android.server.usage;  import android.app.usage.TimeSparseArray; +import android.app.usage.UsageEvents;  import android.app.usage.UsageStats;  import android.app.usage.UsageStatsManager;  import android.os.Build; @@ -25,6 +26,10 @@ import android.util.AtomicFile;  import android.util.Slog;  import android.util.TimeUtils; +import com.android.internal.annotations.VisibleForTesting; + +import libcore.io.IoUtils; +  import java.io.BufferedReader;  import java.io.BufferedWriter;  import java.io.ByteArrayInputStream; @@ -32,18 +37,49 @@ import java.io.ByteArrayOutputStream;  import java.io.DataInputStream;  import java.io.DataOutputStream;  import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream;  import java.io.FileReader;  import java.io.FileWriter;  import java.io.FilenameFilter; +import java.io.InputStream;  import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption;  import java.util.ArrayList;  import java.util.List;  /** - * Provides an interface to query for UsageStat data from an XML database. + * Provides an interface to query for UsageStat data from a Protocol Buffer database. + * + * Prior to version 4, UsageStatsDatabase used XML to store Usage Stats data to disk. + * When the UsageStatsDatabase version is upgraded, the files on disk are migrated to the new + * version on init. The steps of migration are as follows: + * 1) Check if version upgrade breadcrumb exists on disk, if so skip to step 4. + * 2) Copy current files to versioned backup files. + * 3) Write a temporary breadcrumb file with some info about the backed up files. + * 4) Deserialize a versioned backup file using the info written to the breadcrumb for the + * correct deserialization methodology. + * 5) Reserialize the data read from the file with the new version format and replace the old files + * 6) Repeat Step 3 and 4 for each versioned backup file matching the breadcrumb file. + * 7) Update the version file with the new version and build fingerprint. + * 8) Delete the versioned backup files (unless flagged to be kept). + * 9) Delete the breadcrumb file. + * + * Performing the upgrade steps in this order, protects against unexpected shutdowns mid upgrade + * + * A versioned backup file is simply a copy of a Usage Stats file with some extra info embedded in + * the file name. The structure of the versioned backup filename is as followed: + * (original file name).(backup timestamp).(original file version).vak + * + * During the version upgrade process, the new upgraded file will have it's name set to the original + * file name. The backup timestamp helps distinguish between versioned backups if multiple upgrades + * and downgrades have taken place. The original file version denotes how to parse the file.   */  public class UsageStatsDatabase { -    private static final int CURRENT_VERSION = 3; +    private static final int DEFAULT_CURRENT_VERSION = 4;      // Current version of the backup schema      static final int BACKUP_VERSION = 1; @@ -52,10 +88,16 @@ public class UsageStatsDatabase {      // same as UsageStatsBackupHelper.KEY_USAGE_STATS      static final String KEY_USAGE_STATS = "usage_stats"; +    // Persist versioned backup files. +    // Should be false, except when testing new versions +    // STOPSHIP: b/111422946 this should be false on launch +    static final boolean KEEP_VAK_FILES = true;      private static final String TAG = "UsageStatsDatabase"; -    private static final boolean DEBUG = UsageStatsService.DEBUG; +    // STOPSHIP: b/111422946 this should be boolean DEBUG = UsageStatsService.DEBUG; on launch +    private static final boolean DEBUG = true;      private static final String BAK_SUFFIX = ".bak"; +    private static final String VERSIONED_BAK_SUFFIX = ".vak";      private static final String CHECKED_IN_SUFFIX = UsageStatsXml.CHECKED_IN_SUFFIX;      private static final String RETENTION_LEN_KEY = "ro.usagestats.chooser.retention";      private static final int SELECTION_LOG_RETENTION_LEN = @@ -66,21 +108,40 @@ public class UsageStatsDatabase {      private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;      private final UnixCalendar mCal;      private final File mVersionFile; +    // If this file exists on disk, UsageStatsDatabase is in the middle of migrating files to a new +    // version. If this file exists on boot, the upgrade was interrupted and needs to be picked up +    // where it left off. +    private final File mUpdateBreadcrumb; +    // Current version of the database files schema +    private final int mCurrentVersion;      private boolean mFirstUpdate;      private boolean mNewUpdate; -    public UsageStatsDatabase(File dir) { -        mIntervalDirs = new File[] { +    /** +     * UsageStatsDatabase constructor that allows setting the version number. +     * This should only be used for testing. +     * +     * @hide +     */ +    @VisibleForTesting +    public UsageStatsDatabase(File dir, int version) { +        mIntervalDirs = new File[]{                  new File(dir, "daily"),                  new File(dir, "weekly"),                  new File(dir, "monthly"),                  new File(dir, "yearly"),          }; +        mCurrentVersion = version;          mVersionFile = new File(dir, "version"); +        mUpdateBreadcrumb = new File(dir, "breadcrumb");          mSortedStatFiles = new TimeSparseArray[mIntervalDirs.length];          mCal = new UnixCalendar(0);      } +    public UsageStatsDatabase(File dir) { +        this(dir, DEFAULT_CURRENT_VERSION); +    } +      /**       * Initialize any directories required and index what stats are available.       */ @@ -154,7 +215,7 @@ public class UsageStatsDatabase {              try {                  IntervalStats stats = new IntervalStats();                  for (int i = start; i < fileCount - 1; i++) { -                    UsageStatsXml.read(files.valueAt(i), stats); +                    readLocked(files.valueAt(i), stats);                      if (!checkinAction.checkin(stats)) {                          return false;                      } @@ -190,7 +251,7 @@ public class UsageStatsDatabase {          final FilenameFilter backupFileFilter = new FilenameFilter() {              @Override              public boolean accept(File dir, String name) { -                return !name.endsWith(BAK_SUFFIX); +                return !name.endsWith(BAK_SUFFIX) && !name.endsWith(VERSIONED_BAK_SUFFIX);              }          }; @@ -210,7 +271,7 @@ public class UsageStatsDatabase {                  for (File f : files) {                      final AtomicFile af = new AtomicFile(f);                      try { -                        mSortedStatFiles[i].put(UsageStatsXml.parseBeginTime(af), af); +                        mSortedStatFiles[i].put(parseBeginTime(af), af);                      } catch (IOException e) {                          Slog.e(TAG, "failed to index file: " + f, e);                      } @@ -252,14 +313,32 @@ public class UsageStatsDatabase {              version = 0;          } -        if (version != CURRENT_VERSION) { -            Slog.i(TAG, "Upgrading from version " + version + " to " + CURRENT_VERSION); -            doUpgradeLocked(version); +        if (version != mCurrentVersion) { +            Slog.i(TAG, "Upgrading from version " + version + " to " + mCurrentVersion); +            if (!mUpdateBreadcrumb.exists()) { +                doUpgradeLocked(version); +            } else { +                Slog.i(TAG, "Version upgrade breadcrumb found on disk! Continuing version upgrade"); +            } + +            if (mUpdateBreadcrumb.exists()) { +                int previousVersion; +                long token; +                try (BufferedReader reader = new BufferedReader( +                        new FileReader(mUpdateBreadcrumb))) { +                    token = Long.parseLong(reader.readLine()); +                    previousVersion = Integer.parseInt(reader.readLine()); +                } catch (NumberFormatException | IOException e) { +                    Slog.e(TAG, "Failed read version upgrade breadcrumb"); +                    throw new RuntimeException(e); +                } +                continueUpgradeLocked(previousVersion, token); +            }          } -        if (version != CURRENT_VERSION || mNewUpdate) { +        if (version != mCurrentVersion || mNewUpdate) {              try (BufferedWriter writer = new BufferedWriter(new FileWriter(mVersionFile))) { -                writer.write(Integer.toString(CURRENT_VERSION)); +                writer.write(Integer.toString(mCurrentVersion));                  writer.write("\n");                  writer.write(currentFingerprint);                  writer.write("\n"); @@ -269,6 +348,14 @@ public class UsageStatsDatabase {                  throw new RuntimeException(e);              }          } + +        if (mUpdateBreadcrumb.exists()) { +            // Files should be up to date with current version. Clear the version update breadcrumb +            if (!KEEP_VAK_FILES) { +                removeVersionedBackupFiles(); +            } +            mUpdateBreadcrumb.delete(); +        }      }      private String getBuildFingerprint() { @@ -290,6 +377,119 @@ public class UsageStatsDatabase {                      }                  }              } +        } else { +            // Turn all current usage stats files into versioned backup files +            final long token = System.currentTimeMillis(); +            final FilenameFilter backupFileFilter = new FilenameFilter() { +                @Override +                public boolean accept(File dir, String name) { +                    return !name.endsWith(BAK_SUFFIX) && !name.endsWith(VERSIONED_BAK_SUFFIX); +                } +            }; + +            for (int i = 0; i < mIntervalDirs.length; i++) { +                File[] files = mIntervalDirs[i].listFiles(backupFileFilter); +                if (files != null) { +                    for (int j = 0; j < files.length; j++) { +                        final File backupFile = new File( +                                files[j].toString() + "." + Long.toString(token) + "." +                                        + Integer.toString(thisVersion) + VERSIONED_BAK_SUFFIX); +                        if (DEBUG) { +                            Slog.d(TAG, "Creating versioned (" + Integer.toString(thisVersion) +                                    + ") backup of " + files[j].toString() +                                    + " stat files for interval " +                                    + i + " to " + backupFile.toString()); +                        } + +                        try { +                            // Backup file should not already exist, but make sure it doesn't +                            Files.deleteIfExists(backupFile.toPath()); +                            Files.move(files[j].toPath(), backupFile.toPath(), +                                    StandardCopyOption.ATOMIC_MOVE); +                        } catch (IOException e) { +                            Slog.e(TAG, "Failed to back up file : " + files[j].toString()); +                            throw new RuntimeException(e); +                        } +                    } +                } +            } + +            // Leave a breadcrumb behind noting that all the usage stats have been copied to a +            // versioned backup. +            BufferedWriter writer = null; +            try { +                writer = new BufferedWriter(new FileWriter(mUpdateBreadcrumb)); +                writer.write(Long.toString(token)); +                writer.write("\n"); +                writer.write(Integer.toString(thisVersion)); +                writer.write("\n"); +                writer.flush(); +            } catch (IOException e) { +                Slog.e(TAG, "Failed to write new version upgrade breadcrumb"); +                throw new RuntimeException(e); +            } finally { +                IoUtils.closeQuietly(writer); +            } +        } +    } + +    private void continueUpgradeLocked(int version, long token) { +        // Read all the backed ups for the specified version and rewrite them with the current +        // version's file format. +        final FilenameFilter versionedBackupFileFilter = new FilenameFilter() { +            @Override +            public boolean accept(File dir, String name) { +                return name.endsWith("." + Long.toString(token) + "." + Integer.toString(version) +                        + VERSIONED_BAK_SUFFIX); +            } +        }; + +        for (int i = 0; i < mIntervalDirs.length; i++) { +            File[] files = mIntervalDirs[i].listFiles(versionedBackupFileFilter); +            if (files != null) { +                for (int j = 0; j < files.length; j++) { +                    if (DEBUG) { +                        Slog.d(TAG, +                                "Upgrading " + files[j].toString() + " to version (" +                                        + Integer.toString( +                                        mCurrentVersion) + ") for interval " + i); +                    } +                    try { +                        IntervalStats stats = new IntervalStats(); +                        readLocked(new AtomicFile(files[j]), stats, version); +                        writeLocked(new AtomicFile(new File(mIntervalDirs[i], +                                Long.toString(stats.beginTime))), stats, mCurrentVersion); +                    } catch (IOException e) { +                        Slog.e(TAG, +                                "Failed to upgrade versioned backup file : " + files[j].toString()); +                        throw new RuntimeException(e); +                    } +                } +            } +        } +    } + +    private void removeVersionedBackupFiles() { +        final FilenameFilter versionedBackupFileFilter = new FilenameFilter() { +            @Override +            public boolean accept(File dir, String name) { +                return name.endsWith(VERSIONED_BAK_SUFFIX); +            } +        }; + +        for (int i = 0; i < mIntervalDirs.length; i++) { +            File[] files = mIntervalDirs[i].listFiles(versionedBackupFileFilter); +            if (files != null) { +                for (int j = 0; j < files.length; j++) { +                    if (DEBUG) { +                        Slog.d(TAG, +                                "Removing " + files[j].toString() + " for interval " + i); +                    } +                    if (!files[j].delete()) { +                        Slog.e(TAG, "Failed to delete file : " + files[j].toString()); +                    } +                } +            }          }      } @@ -357,7 +557,7 @@ public class UsageStatsDatabase {              try {                  final AtomicFile f = mSortedStatFiles[intervalType].valueAt(fileCount - 1);                  IntervalStats stats = new IntervalStats(); -                UsageStatsXml.read(f, stats); +                readLocked(f, stats);                  return stats;              } catch (IOException e) {                  Slog.e(TAG, "Failed to read usage stats file", e); @@ -379,8 +579,8 @@ public class UsageStatsDatabase {           * which means you should make a copy of the data before adding it to the           * <code>accumulatedResult</code> list.           * -         * @param stats The {@link IntervalStats} object selected. -         * @param mutable Whether or not the data inside the stats object is mutable. +         * @param stats             The {@link IntervalStats} object selected. +         * @param mutable           Whether or not the data inside the stats object is mutable.           * @param accumulatedResult The list to which to add extracted data.           */          void combine(IntervalStats stats, boolean mutable, List<T> accumulatedResult); @@ -443,7 +643,7 @@ public class UsageStatsDatabase {                  }                  try { -                    UsageStatsXml.read(f, stats); +                    readLocked(f, stats);                      if (beginTime < stats.endTime) {                          combiner.combine(stats, false, results);                      } @@ -523,14 +723,9 @@ public class UsageStatsDatabase {          File[] files = dir.listFiles();          if (files != null) {              for (File f : files) { -                String path = f.getPath(); -                if (path.endsWith(BAK_SUFFIX)) { -                    f = new File(path.substring(0, path.length() - BAK_SUFFIX.length())); -                } -                  long beginTime;                  try { -                    beginTime = UsageStatsXml.parseBeginTime(f); +                    beginTime = parseBeginTime(f);                  } catch (IOException e) {                      beginTime = 0;                  } @@ -542,18 +737,13 @@ public class UsageStatsDatabase {          }      } -    private static void pruneChooserCountsOlderThan(File dir, long expiryTime) { +    private void pruneChooserCountsOlderThan(File dir, long expiryTime) {          File[] files = dir.listFiles();          if (files != null) {              for (File f : files) { -                String path = f.getPath(); -                if (path.endsWith(BAK_SUFFIX)) { -                    f = new File(path.substring(0, path.length() - BAK_SUFFIX.length())); -                } -                  long beginTime;                  try { -                    beginTime = UsageStatsXml.parseBeginTime(f); +                    beginTime = parseBeginTime(f);                  } catch (IOException e) {                      beginTime = 0;                  } @@ -562,7 +752,7 @@ public class UsageStatsDatabase {                      try {                          final AtomicFile af = new AtomicFile(f);                          final IntervalStats stats = new IntervalStats(); -                        UsageStatsXml.read(af, stats); +                        readLocked(af, stats);                          final int pkgCount = stats.packageStats.size();                          for (int i = 0; i < pkgCount; i++) {                              UsageStats pkgStats = stats.packageStats.valueAt(i); @@ -570,7 +760,7 @@ public class UsageStatsDatabase {                                  pkgStats.mChooserCounts.clear();                              }                          } -                        UsageStatsXml.write(af, stats); +                        writeLocked(af, stats);                      } catch (IOException e) {                          Slog.e(TAG, "Failed to delete chooser counts from usage stats file", e);                      } @@ -579,6 +769,222 @@ public class UsageStatsDatabase {          }      } + +    private static long parseBeginTime(AtomicFile file) throws IOException { +        return parseBeginTime(file.getBaseFile()); +    } + +    private static long parseBeginTime(File file) throws IOException { +        String name = file.getName(); + +        // Parse out the digits from the the front of the file name +        for (int i = 0; i < name.length(); i++) { +            final char c = name.charAt(i); +            if (c < '0' || c > '9') { +                // found first char that is not a digit. +                name = name.substring(0, i); +                break; +            } +        } + +        try { +            return Long.parseLong(name); +        } catch (NumberFormatException e) { +            throw new IOException(e); +        } +    } + +    private void writeLocked(AtomicFile file, IntervalStats stats) throws IOException { +        writeLocked(file, stats, mCurrentVersion); +    } + +    private static void writeLocked(AtomicFile file, IntervalStats stats, int version) +            throws IOException { +        FileOutputStream fos = file.startWrite(); +        try { +            writeLocked(fos, stats, version); +            file.finishWrite(fos); +            fos = null; +        } finally { +            // When fos is null (successful write), this will no-op +            file.failWrite(fos); +        } +    } + +    private void writeLocked(OutputStream out, IntervalStats stats) throws IOException { +        writeLocked(out, stats, mCurrentVersion); +    } + +    private static void writeLocked(OutputStream out, IntervalStats stats, int version) +            throws IOException { +        switch (version) { +            case 1: +            case 2: +            case 3: +                UsageStatsXml.write(out, stats); +                break; +            case 4: +                UsageStatsProto.write(out, stats); +                break; +            default: +                throw new RuntimeException( +                        "Unhandled UsageStatsDatabase version: " + Integer.toString(version) +                                + " on write."); +        } +    } + +    private void readLocked(AtomicFile file, IntervalStats statsOut) throws IOException { +        readLocked(file, statsOut, mCurrentVersion); +    } + +    private static void readLocked(AtomicFile file, IntervalStats statsOut, int version) +            throws IOException { +        try { +            FileInputStream in = file.openRead(); +            try { +                statsOut.beginTime = parseBeginTime(file); +                readLocked(in, statsOut, version); +                statsOut.lastTimeSaved = file.getLastModifiedTime(); +            } finally { +                try { +                    in.close(); +                } catch (IOException e) { +                    // Empty +                } +            } +        } catch (FileNotFoundException e) { +            Slog.e(TAG, "UsageStatsDatabase", e); +            throw e; +        } +        // STOPSHIP: b/111422946, b/115429334 +        // Everything below this comment is sanity check against the new database version. +        // After the new version has soaked for some time the following should removed. +        // The goal of this check is to make sure the the ProtoInputStream is properly reading from +        // the UsageStats files. +        final StringBuilder sb = new StringBuilder(); +        final int failureLogLimit = 10; +        int failures = 0; + +        final int packagesSize = statsOut.packageStats.size(); +        for (int i = 0; i < packagesSize; i++) { +            final UsageStats stat = statsOut.packageStats.valueAt(i); +            if (stat == null) { +                // ArrayMap may contain null values, skip them +                continue; +            } +            if (stat.mPackageName.isEmpty()) { +                if (failures++ < failureLogLimit) { +                    sb.append("\nUnexpected empty usage stats package name loaded"); +                } +            } +            if (stat.mBeginTimeStamp > statsOut.endTime) { +                if (failures++ < failureLogLimit) { +                    sb.append("\nUnreasonable usage stats stat begin timestamp "); +                    sb.append(stat.mBeginTimeStamp); +                    sb.append(" loaded (beginTime : "); +                    sb.append(statsOut.beginTime); +                    sb.append(", endTime : "); +                    sb.append(statsOut.endTime); +                    sb.append(")"); +                } +            } +            if (stat.mEndTimeStamp > statsOut.endTime) { +                if (failures++ < failureLogLimit) { +                    sb.append("\nUnreasonable usage stats stat end timestamp "); +                    sb.append(stat.mEndTimeStamp); +                    sb.append(" loaded (beginTime : "); +                    sb.append(statsOut.beginTime); +                    sb.append(", endTime : "); +                    sb.append(statsOut.endTime); +                    sb.append(")"); +                } +            } +            if (stat.mLastTimeUsed > statsOut.endTime) { +                if (failures++ < failureLogLimit) { +                    sb.append("\nUnreasonable usage stats stat last used timestamp "); +                    sb.append(stat.mLastTimeUsed); +                    sb.append(" loaded (beginTime : "); +                    sb.append(statsOut.beginTime); +                    sb.append(", endTime : "); +                    sb.append(statsOut.endTime); +                    sb.append(")"); +                } +            } +        } + +        if (statsOut.events != null) { +            final int eventSize = statsOut.events.size(); +            for (int i = 0; i < eventSize; i++) { +                final UsageEvents.Event event = statsOut.events.get(i); +                if (event.mPackage.isEmpty()) { +                    if (failures++ < failureLogLimit) { +                        sb.append("\nUnexpected empty empty package name loaded"); +                    } +                } +                if (event.mTimeStamp < statsOut.beginTime || event.mTimeStamp > statsOut.endTime) { +                    if (failures++ < failureLogLimit) { +                        sb.append("\nUnexpected event timestamp "); +                        sb.append(event.mTimeStamp); +                        sb.append(" loaded (beginTime : "); +                        sb.append(statsOut.beginTime); +                        sb.append(", endTime : "); +                        sb.append(statsOut.endTime); +                        sb.append(")"); +                    } +                } +                if (event.mEventType < 0 || event.mEventType > UsageEvents.Event.MAX_EVENT_TYPE) { +                    if (failures++ < failureLogLimit) { +                        sb.append("\nUnexpected event type "); +                        sb.append(event.mEventType); +                        sb.append(" loaded"); +                    } +                } +                if ((event.mFlags & ~UsageEvents.Event.VALID_FLAG_BITS) != 0) { +                    if (failures++ < failureLogLimit) { +                        sb.append("\nUnexpected event flag bit 0b"); +                        sb.append(Integer.toBinaryString(event.mFlags)); +                        sb.append(" loaded"); +                    } +                } +            } +        } + +        if (failures != 0) { +            if (failures > failureLogLimit) { +                sb.append("\nFailure log limited ("); +                sb.append(failures); +                sb.append(" total failures found!)"); +            } +            sb.append("\nError found in:\n"); +            sb.append(file.getBaseFile().getAbsolutePath()); +            sb.append("\nPlease go to b/115429334 to help root cause this issue"); +            Slog.wtf(TAG,sb.toString()); +        } +    } + +    private void readLocked(InputStream in, IntervalStats statsOut) throws IOException { +        readLocked(in, statsOut, mCurrentVersion); +    } + +    private static void readLocked(InputStream in, IntervalStats statsOut, int version) +            throws IOException { +        switch (version) { +            case 1: +            case 2: +            case 3: +                UsageStatsXml.read(in, statsOut); +                break; +            case 4: +                UsageStatsProto.read(in, statsOut); +                break; +            default: +                throw new RuntimeException( +                        "Unhandled UsageStatsDatabase version: " + Integer.toString(version) +                                + " on read."); +        } + +    } +      /**       * Update the stats in the database. They may not be written to disk immediately.       */ @@ -596,7 +1002,7 @@ public class UsageStatsDatabase {                  mSortedStatFiles[intervalType].put(stats.beginTime, f);              } -            UsageStatsXml.write(f, stats); +            writeLocked(f, stats);              stats.lastTimeSaved = f.getLastModifiedTime();          }      } @@ -730,7 +1136,7 @@ public class UsageStatsDatabase {              throws IOException {          IntervalStats stats = new IntervalStats();          try { -            UsageStatsXml.read(statsFile, stats); +            readLocked(statsFile, stats);          } catch (IOException e) {              Slog.e(TAG, "Failed to read usage stats file", e);              out.writeInt(0); @@ -756,12 +1162,12 @@ public class UsageStatsDatabase {          if (stats.events != null) stats.events.clear();      } -    private static byte[] serializeIntervalStats(IntervalStats stats) { +    private byte[] serializeIntervalStats(IntervalStats stats) {          ByteArrayOutputStream baos = new ByteArrayOutputStream();          DataOutputStream out = new DataOutputStream(baos);          try {              out.writeLong(stats.beginTime); -            UsageStatsXml.write(out, stats); +            writeLocked(out, stats);          } catch (IOException ioe) {              Slog.d(TAG, "Serializing IntervalStats Failed", ioe);              baos.reset(); @@ -769,13 +1175,13 @@ public class UsageStatsDatabase {          return baos.toByteArray();      } -    private static IntervalStats deserializeIntervalStats(byte[] data) { +    private IntervalStats deserializeIntervalStats(byte[] data) {          ByteArrayInputStream bais = new ByteArrayInputStream(data);          DataInputStream in = new DataInputStream(bais);          IntervalStats stats = new IntervalStats();          try {              stats.beginTime = in.readLong(); -            UsageStatsXml.read(in, stats); +            readLocked(in, stats);          } catch (IOException ioe) {              Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe);              stats = null; diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java new file mode 100644 index 000000000000..30d303f426bf --- /dev/null +++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.usage; + +import android.app.usage.ConfigurationStats; +import android.app.usage.EventList; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; +import android.content.res.Configuration; +import android.util.ArrayMap; + +import android.util.Slog; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.List; + +/** + * UsageStats reader/writer for Protocol Buffer format + */ +final class UsageStatsProto { +    private static String TAG = "UsageStatsProto"; + +    // Static-only utility class. +    private UsageStatsProto() {} + +    private static List<String> readStringPool(ProtoInputStream proto) throws IOException { + +        final long token = proto.start(IntervalStatsProto.STRINGPOOL); +        List<String> stringPool; +        if (proto.isNextField(IntervalStatsProto.StringPool.SIZE)) { +            stringPool = new ArrayList(proto.readInt(IntervalStatsProto.StringPool.SIZE)); +        } else { +            stringPool = new ArrayList(); +        } +        while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +            switch (proto.getFieldNumber()) { +                case (int) IntervalStatsProto.StringPool.STRINGS: +                    stringPool.add(proto.readString(IntervalStatsProto.StringPool.STRINGS)); +                    break; +            } +        } +        proto.end(token); +        return stringPool; +    } + +    private static void loadUsageStats(ProtoInputStream proto, long fieldId, +            IntervalStats statsOut, List<String> stringPool) +            throws IOException { + +        final long token = proto.start(fieldId); +        UsageStats stats; +        if (proto.isNextField(IntervalStatsProto.UsageStats.PACKAGE_INDEX)) { +            // Fast path reading the package name index. Most cases this should work since it is +            // written first +            stats = statsOut.getOrCreateUsageStats( +                    stringPool.get(proto.readInt(IntervalStatsProto.UsageStats.PACKAGE_INDEX) - 1)); +        } else if (proto.isNextField(IntervalStatsProto.UsageStats.PACKAGE)) { +            // No package index, try package name instead +            stats = statsOut.getOrCreateUsageStats( +                    proto.readString(IntervalStatsProto.UsageStats.PACKAGE)); +        } else { +            // Temporarily store collected data to a UsageStats object. This is not efficient. +            stats = new UsageStats(); +        } + +        while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { +            switch (proto.getFieldNumber()) { +                case (int) IntervalStatsProto.UsageStats.PACKAGE: +                    // Fast track failed from some reason, add UsageStats object to statsOut now +                    UsageStats tempPackage = statsOut.getOrCreateUsageStats( +                            proto.readString(IntervalStatsProto.UsageStats.PACKAGE)); +                    tempPackage.mLastTimeUsed = stats.mLastTimeUsed; +                    tempPackage.mTotalTimeInForeground = stats.mTotalTimeInForeground; +                    tempPackage.mLastEvent = stats.mLastEvent; +                    tempPackage.mAppLaunchCount = stats.mAppLaunchCount; +                    stats = tempPackage; +                    break; +                case (int) IntervalStatsProto.UsageStats.PACKAGE_INDEX: +                    // Fast track failed from some reason, add UsageStats object to statsOut now +                    UsageStats tempPackageIndex = statsOut.getOrCreateUsageStats(stringPool.get( +                            proto.readInt(IntervalStatsProto.UsageStats.PACKAGE_INDEX) - 1)); +                    tempPackageIndex.mLastTimeUsed = stats.mLastTimeUsed; +                    tempPackageIndex.mTotalTimeInForeground = stats.mTotalTimeInForeground; +                    tempPackageIndex.mLastEvent = stats.mLastEvent; +                    tempPackageIndex.mAppLaunchCount = stats.mAppLaunchCount; +                    stats = tempPackageIndex; +                    break; +                case (int) IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS: +                    stats.mLastTimeUsed = statsOut.beginTime + proto.readLong( +                            IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS); +                    break; +                case (int) IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS: +                    stats.mTotalTimeInForeground = proto.readLong( +                            IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS); +                    break; +                case (int) IntervalStatsProto.UsageStats.LAST_EVENT: +                    stats.mLastEvent = proto.readInt(IntervalStatsProto.UsageStats.LAST_EVENT); +                    break; +                case (int) IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT: +                    stats.mAppLaunchCount = proto.readInt( +                            IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT); +                    break; +                case (int) IntervalStatsProto.UsageStats.CHOOSER_ACTIONS: +                    final long chooserToken = proto.start( +                            IntervalStatsProto.UsageStats.CHOOSER_ACTIONS); +                    loadChooserCounts(proto, stats); +                    proto.end(chooserToken); +                    break; +            } +        } +        if (stats.mLastTimeUsed == 0) { +            // mLastTimeUsed was not assigned, assume default value of 0 plus beginTime; +            stats.mLastTimeUsed = statsOut.beginTime; +        } +        proto.end(token); +    } + +    private static void loadCountAndTime(ProtoInputStream proto, long fieldId, +            IntervalStats.EventTracker tracker) throws IOException { +        final long token = proto.start(fieldId); +        while (true) { +            switch (proto.nextField()) { +                case (int) IntervalStatsProto.CountAndTime.COUNT: +                    tracker.count = proto.readInt(IntervalStatsProto.CountAndTime.COUNT); +                    break; +                case (int) IntervalStatsProto.CountAndTime.TIME_MS: +                    tracker.duration = proto.readLong(IntervalStatsProto.CountAndTime.TIME_MS); +                    break; +                case ProtoInputStream.NO_MORE_FIELDS: +                    proto.end(token); +                    return; +            } +        } +    } + +    private static void loadChooserCounts(ProtoInputStream proto, UsageStats usageStats) +            throws IOException { +        if (usageStats.mChooserCounts == null) { +            usageStats.mChooserCounts = new ArrayMap<>(); +        } +        String action = null; +        ArrayMap<String, Integer> counts; +        if (proto.isNextField(IntervalStatsProto.UsageStats.ChooserAction.NAME)) { +            // Fast path reading the action name. Most cases this should work since it is written +            // first +            action = proto.readString(IntervalStatsProto.UsageStats.ChooserAction.NAME); +            counts = usageStats.mChooserCounts.get(action); +            if (counts == null) { +                counts = new ArrayMap<>(); +                usageStats.mChooserCounts.put(action, counts); +            } +        } else { +            // Temporarily store collected data to an ArrayMap. This is not efficient. +            counts = new ArrayMap<>(); +        } + +        while (true) { +            switch (proto.nextField()) { +                case (int) IntervalStatsProto.UsageStats.ChooserAction.NAME: +                    // Fast path failed from some reason, add the ArrayMap object to usageStats now +                    action = proto.readString(IntervalStatsProto.UsageStats.ChooserAction.NAME); +                    usageStats.mChooserCounts.put(action, counts); +                    break; +                case (int) IntervalStatsProto.UsageStats.ChooserAction.COUNTS: +                    final long token = proto.start( +                            IntervalStatsProto.UsageStats.ChooserAction.COUNTS); +                    loadCountsForAction(proto, counts); +                    proto.end(token); +                case ProtoInputStream.NO_MORE_FIELDS: +                    if (action == null) { +                        // default string +                        usageStats.mChooserCounts.put("", counts); +                    } +                    return; +            } +        } +    } + +    private static void loadCountsForAction(ProtoInputStream proto, +            ArrayMap<String, Integer> counts) throws IOException { +        String category = null; +        int count = 0; +        while (true) { +            switch (proto.nextField()) { +                case (int) IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.NAME: +                    category = proto.readString( +                            IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.NAME); +                    break; +                case (int) IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.COUNT: +                    count = proto.readInt( +                            IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.COUNT); +                    break; +                case ProtoInputStream.NO_MORE_FIELDS: +                    if (category == null) { +                        counts.put("", count); +                    } else { +                        counts.put(category, count); +                    } +                    return; +            } +        } +    } + +    private static void loadConfigStats(ProtoInputStream proto, long fieldId, +            IntervalStats statsOut) throws IOException { +        final long token = proto.start(fieldId); +        boolean configActive = false; +        final Configuration config = new Configuration(); +        ConfigurationStats configStats; +        if (proto.isNextField(IntervalStatsProto.Configuration.CONFIG)) { +            // Fast path reading the configuration. Most cases this should work since it is +            // written first +            config.readFromProto(proto, IntervalStatsProto.Configuration.CONFIG); +            configStats = statsOut.getOrCreateConfigurationStats(config); +        } else { +            // Temporarily store collected data to a ConfigurationStats object. This is not +            // efficient. +            configStats = new ConfigurationStats(); +        } +        while (true) { +            switch (proto.nextField()) { +                case (int) IntervalStatsProto.Configuration.CONFIG: +                    // Fast path failed from some reason, add ConfigStats object to statsOut now +                    config.readFromProto(proto, IntervalStatsProto.Configuration.CONFIG); +                    final ConfigurationStats temp = statsOut.getOrCreateConfigurationStats(config); +                    temp.mLastTimeActive = configStats.mLastTimeActive; +                    temp.mTotalTimeActive = configStats.mTotalTimeActive; +                    temp.mActivationCount = configStats.mActivationCount; +                    configStats = temp; +                    break; +                case (int) IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS: +                    configStats.mLastTimeActive = statsOut.beginTime + proto.readLong( +                            IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS); +                    break; +                case (int) IntervalStatsProto.Configuration.TOTAL_TIME_ACTIVE_MS: +                    configStats.mTotalTimeActive = proto.readLong( +                            IntervalStatsProto.Configuration.TOTAL_TIME_ACTIVE_MS); +                    break; +                case (int) IntervalStatsProto.Configuration.COUNT: +                    configStats.mActivationCount = proto.readInt( +                            IntervalStatsProto.Configuration.COUNT); +                    break; +                case (int) IntervalStatsProto.Configuration.ACTIVE: +                    configActive = proto.readBoolean(IntervalStatsProto.Configuration.ACTIVE); +                    break; +                case ProtoInputStream.NO_MORE_FIELDS: +                    if (configStats.mLastTimeActive == 0) { +                        //mLastTimeActive was not assigned, assume default value of 0 plus beginTime +                        configStats.mLastTimeActive = statsOut.beginTime; +                    } +                    if (configActive) { +                        statsOut.activeConfiguration = configStats.mConfiguration; +                    } +                    proto.end(token); +                    return; +            } +        } +    } + +    private static void loadEvent(ProtoInputStream proto, long fieldId, IntervalStats statsOut, +            List<String> stringPool) throws IOException { +        final long token = proto.start(fieldId); +        UsageEvents.Event event = statsOut.buildEvent(proto, stringPool); +        proto.end(token); +        if (event.mPackage == null) { +            throw new ProtocolException("no package field present"); +        } + +        if (statsOut.events == null) { +            statsOut.events = new EventList(); +        } +        statsOut.events.insert(event); +    } + +    private static void writeStringPool(ProtoOutputStream proto, final IntervalStats stats) +            throws IOException { +        final long token = proto.start(IntervalStatsProto.STRINGPOOL); +        final int size = stats.mStringCache.size(); +        proto.write(IntervalStatsProto.StringPool.SIZE, size); +        for (int i = 0; i < size; i++) { +            proto.write(IntervalStatsProto.StringPool.STRINGS, stats.mStringCache.valueAt(i)); +        } +        proto.end(token); +    } + +    private static void writeUsageStats(ProtoOutputStream proto, long fieldId, +            final IntervalStats stats, final UsageStats usageStats) throws IOException { +        final long token = proto.start(fieldId); +        // Write the package name first, so loadUsageStats can avoid creating an extra object +        final int packageIndex = stats.mStringCache.indexOf(usageStats.mPackageName); +        if (packageIndex >= 0) { +            proto.write(IntervalStatsProto.UsageStats.PACKAGE_INDEX, packageIndex + 1); +        } else { +            // Package not in Stringpool for some reason, write full string instead +            Slog.w(TAG, "UsageStats package name (" + usageStats.mPackageName +                    + ") not found in IntervalStats string cache"); +            proto.write(IntervalStatsProto.UsageStats.PACKAGE, usageStats.mPackageName); +        } +        proto.write(IntervalStatsProto.UsageStats.LAST_TIME_ACTIVE_MS, +                usageStats.mLastTimeUsed - stats.beginTime); +        proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_ACTIVE_MS, +                usageStats.mTotalTimeInForeground); +        proto.write(IntervalStatsProto.UsageStats.LAST_EVENT, usageStats.mLastEvent); +        proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount); +        writeChooserCounts(proto, usageStats); +        proto.end(token); +    } + +    private static void writeCountAndTime(ProtoOutputStream proto, long fieldId, int count, +            long time) throws IOException { +        final long token = proto.start(fieldId); +        proto.write(IntervalStatsProto.CountAndTime.COUNT, count); +        proto.write(IntervalStatsProto.CountAndTime.TIME_MS, time); +        proto.end(token); +    } + + +    private static void writeChooserCounts(ProtoOutputStream proto, final UsageStats usageStats) +            throws IOException { +        if (usageStats == null || usageStats.mChooserCounts == null +                || usageStats.mChooserCounts.keySet().isEmpty()) { +            return; +        } +        final int chooserCountSize = usageStats.mChooserCounts.size(); +        for (int i = 0; i < chooserCountSize; i++) { +            final String action = usageStats.mChooserCounts.keyAt(i); +            final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i); +            if (action == null || counts == null || counts.isEmpty()) { +                continue; +            } +            final long token = proto.start(IntervalStatsProto.UsageStats.CHOOSER_ACTIONS); +            proto.write(IntervalStatsProto.UsageStats.ChooserAction.NAME, action); +            writeCountsForAction(proto, counts); +            proto.end(token); +        } +    } + +    private static void writeCountsForAction(ProtoOutputStream proto, +            ArrayMap<String, Integer> counts) throws IOException { +        final int countsSize = counts.size(); +        for (int i = 0; i < countsSize; i++) { +            String key = counts.keyAt(i); +            int count = counts.valueAt(i); +            if (count > 0) { +                final long token = proto.start(IntervalStatsProto.UsageStats.ChooserAction.COUNTS); +                proto.write(IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.NAME, key); +                proto.write(IntervalStatsProto.UsageStats.ChooserAction.CategoryCount.COUNT, count); +                proto.end(token); +            } +        } +    } + +    private static void writeConfigStats(ProtoOutputStream proto, long fieldId, +            final IntervalStats stats, final ConfigurationStats configStats, boolean isActive) +            throws IOException { +        final long token = proto.start(fieldId); +        configStats.mConfiguration.writeToProto(proto, IntervalStatsProto.Configuration.CONFIG); +        proto.write(IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS, +                configStats.mLastTimeActive - stats.beginTime); +        proto.write(IntervalStatsProto.Configuration.TOTAL_TIME_ACTIVE_MS, +                configStats.mTotalTimeActive); +        proto.write(IntervalStatsProto.Configuration.COUNT, configStats.mActivationCount); +        proto.write(IntervalStatsProto.Configuration.ACTIVE, isActive); +        proto.end(token); + +    } + +    private static void writeEvent(ProtoOutputStream proto, long fieldId, final IntervalStats stats, +            final UsageEvents.Event event) throws IOException { +        final long token = proto.start(fieldId); +        final int packageIndex = stats.mStringCache.indexOf(event.mPackage); +        if (packageIndex >= 0) { +            proto.write(IntervalStatsProto.Event.PACKAGE_INDEX, packageIndex + 1); +        } else { +            // Package not in Stringpool for some reason, write full string instead +            Slog.w(TAG, "Usage event package name (" + event.mPackage +                    + ") not found in IntervalStats string cache"); +            proto.write(IntervalStatsProto.Event.PACKAGE, event.mPackage); +        } +        if (event.mClass != null) { +            final int classIndex = stats.mStringCache.indexOf(event.mClass); +            if (classIndex >= 0) { +                proto.write(IntervalStatsProto.Event.CLASS_INDEX, classIndex + 1); +            } else { +                // Class not in Stringpool for some reason, write full string instead +                Slog.w(TAG, "Usage event class name (" + event.mClass +                        + ") not found in IntervalStats string cache"); +                proto.write(IntervalStatsProto.Event.CLASS, event.mClass); +            } +        } +        proto.write(IntervalStatsProto.Event.TIME_MS, event.mTimeStamp - stats.beginTime); +        proto.write(IntervalStatsProto.Event.FLAGS, event.mFlags); +        proto.write(IntervalStatsProto.Event.TYPE, event.mEventType); +        switch (event.mEventType) { +            case UsageEvents.Event.CONFIGURATION_CHANGE: +                if (event.mConfiguration != null) { +                    event.mConfiguration.writeToProto(proto, IntervalStatsProto.Event.CONFIG); +                } +                break; +            case UsageEvents.Event.SHORTCUT_INVOCATION: +                if (event.mShortcutId != null) { +                    proto.write(IntervalStatsProto.Event.SHORTCUT_ID, event.mShortcutId); +                } +                break; +            case UsageEvents.Event.STANDBY_BUCKET_CHANGED: +                if (event.mBucketAndReason != 0) { +                    proto.write(IntervalStatsProto.Event.STANDBY_BUCKET, event.mBucketAndReason); +                } +                break; +            case UsageEvents.Event.NOTIFICATION_INTERRUPTION: +                if (event.mNotificationChannelId != null) { +                    final int channelIndex = stats.mStringCache.indexOf( +                            event.mNotificationChannelId); +                    if (channelIndex >= 0) { +                        proto.write(IntervalStatsProto.Event.NOTIFICATION_CHANNEL_INDEX, +                                channelIndex + 1); +                    } else { +                        // Channel not in Stringpool for some reason, write full string instead +                        Slog.w(TAG, "Usage event notification channel name (" +                                + event.mNotificationChannelId +                                + ") not found in IntervalStats string cache"); +                        proto.write(IntervalStatsProto.Event.NOTIFICATION_CHANNEL, +                                event.mNotificationChannelId); +                    } +                } +                break; +        } +        proto.end(token); +    } + +    /** +     * Reads from the {@link ProtoInputStream}. +     * +     * @param proto    The proto from which to read events. +     * @param statsOut The stats object to populate with the data from the XML file. +     */ +    public static void read(InputStream in, IntervalStats statsOut) throws IOException { +        final ProtoInputStream proto = new ProtoInputStream(in); +        List<String> stringPool = null; + +        statsOut.packageStats.clear(); +        statsOut.configurations.clear(); +        statsOut.activeConfiguration = null; + +        if (statsOut.events != null) { +            statsOut.events.clear(); +        } + +        while (true) { +            switch (proto.nextField()) { +                case (int) IntervalStatsProto.END_TIME_MS: +                    statsOut.endTime = statsOut.beginTime + proto.readLong( +                            IntervalStatsProto.END_TIME_MS); +                    break; +                case (int) IntervalStatsProto.INTERACTIVE: +                    loadCountAndTime(proto, IntervalStatsProto.INTERACTIVE, +                            statsOut.interactiveTracker); +                    break; +                case (int) IntervalStatsProto.NON_INTERACTIVE: +                    loadCountAndTime(proto, IntervalStatsProto.NON_INTERACTIVE, +                            statsOut.nonInteractiveTracker); +                    break; +                case (int) IntervalStatsProto.KEYGUARD_SHOWN: +                    loadCountAndTime(proto, IntervalStatsProto.KEYGUARD_SHOWN, +                            statsOut.keyguardShownTracker); +                    break; +                case (int) IntervalStatsProto.KEYGUARD_HIDDEN: +                    loadCountAndTime(proto, IntervalStatsProto.KEYGUARD_HIDDEN, +                            statsOut.keyguardHiddenTracker); +                    break; +                case (int) IntervalStatsProto.STRINGPOOL: +                    stringPool = readStringPool(proto); +                    statsOut.mStringCache.addAll(stringPool); +                    break; +                case (int) IntervalStatsProto.PACKAGES: +                    loadUsageStats(proto, IntervalStatsProto.PACKAGES, statsOut, stringPool); +                    break; +                case (int) IntervalStatsProto.CONFIGURATIONS: +                    loadConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, statsOut); +                    break; +                case (int) IntervalStatsProto.EVENT_LOG: +                    loadEvent(proto, IntervalStatsProto.EVENT_LOG, statsOut, stringPool); +                    break; +                case ProtoInputStream.NO_MORE_FIELDS: +                    if (statsOut.endTime == 0) { +                        // endTime not assigned, assume default value of 0 plus beginTime +                        statsOut.endTime = statsOut.beginTime; +                    } +                    return; +            } +        } +    } + +    /** +     * Writes the stats object to an ProtoBuf file. +     * +     * @param proto The serializer to which to write the packageStats data. +     * @param stats The stats object to write to the XML file. +     */ +    public static void write(OutputStream out, IntervalStats stats) throws IOException { +        final ProtoOutputStream proto = new ProtoOutputStream(out); +        proto.write(IntervalStatsProto.END_TIME_MS, stats.endTime - stats.beginTime); +        // String pool should be written before the rest of the usage stats +        writeStringPool(proto, stats); + +        writeCountAndTime(proto, IntervalStatsProto.INTERACTIVE, stats.interactiveTracker.count, +                stats.interactiveTracker.duration); +        writeCountAndTime(proto, IntervalStatsProto.NON_INTERACTIVE, +                stats.nonInteractiveTracker.count, stats.nonInteractiveTracker.duration); +        writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_SHOWN, +                stats.keyguardShownTracker.count, stats.keyguardShownTracker.duration); +        writeCountAndTime(proto, IntervalStatsProto.KEYGUARD_HIDDEN, +                stats.keyguardHiddenTracker.count, stats.keyguardHiddenTracker.duration); + +        final int statsCount = stats.packageStats.size(); +        for (int i = 0; i < statsCount; i++) { +            writeUsageStats(proto, IntervalStatsProto.PACKAGES, stats, +                    stats.packageStats.valueAt(i)); +        } +        final int configCount = stats.configurations.size(); +        for (int i = 0; i < configCount; i++) { +            boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i)); +            writeConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, stats, +                    stats.configurations.valueAt(i), active); +        } +        final int eventCount = stats.events != null ? stats.events.size() : 0; +        for (int i = 0; i < eventCount; i++) { +            writeEvent(proto, IntervalStatsProto.EVENT_LOG, stats, stats.events.get(i)); +        } + +        proto.flush(); +    } +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java index e7db74149b4a..f8d1113e8460 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXml.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java @@ -19,6 +19,9 @@ package com.android.server.usage;  import android.util.AtomicFile;  import android.util.Slog;  import android.util.Xml; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +  import com.android.internal.util.FastXmlSerializer;  import com.android.internal.util.XmlUtils;  import org.xmlpull.v1.XmlPullParser; @@ -33,61 +36,7 @@ public class UsageStatsXml {      private static final String VERSION_ATTR = "version";      static final String CHECKED_IN_SUFFIX = "-c"; -    public static long parseBeginTime(AtomicFile file) throws IOException { -        return parseBeginTime(file.getBaseFile()); -    } - -    public static long parseBeginTime(File file) throws IOException { -        String name = file.getName(); - -        // Eat as many occurrences of -c as possible. This is due to a bug where -c -        // would be appended more than once to a checked-in file, causing a crash -        // on boot when indexing files since Long.parseLong() will puke on anything but -        // a number. -        while (name.endsWith(CHECKED_IN_SUFFIX)) { -            name = name.substring(0, name.length() - CHECKED_IN_SUFFIX.length()); -        } - -        try { -            return Long.parseLong(name); -        } catch (NumberFormatException e) { -            throw new IOException(e); -        } -    } - -    public static void read(AtomicFile file, IntervalStats statsOut) throws IOException { -        try { -            FileInputStream in = file.openRead(); -            try { -                statsOut.beginTime = parseBeginTime(file); -                read(in, statsOut); -                statsOut.lastTimeSaved = file.getLastModifiedTime(); -            } finally { -                try { -                    in.close(); -                } catch (IOException e) { -                    // Empty -                } -            } -        } catch (FileNotFoundException e) { -            Slog.e(TAG, "UsageStats Xml", e); -            throw e; -        } -    } - -    public static void write(AtomicFile file, IntervalStats stats) throws IOException { -        FileOutputStream fos = file.startWrite(); -        try { -            write(fos, stats); -            file.finishWrite(fos); -            fos = null; -        } finally { -            // When fos is null (successful write), this will no-op -            file.failWrite(fos); -        } -    } - -    static void read(InputStream in, IntervalStats statsOut) throws IOException { +    public static void read(InputStream in, IntervalStats statsOut) throws IOException {          XmlPullParser parser = Xml.newPullParser();          try {              parser.setInput(in, "utf-8"); @@ -113,7 +62,7 @@ public class UsageStatsXml {          }      } -    static void write(OutputStream out, IntervalStats stats) throws IOException { +    public static void write(OutputStream out, IntervalStats stats) throws IOException {          FastXmlSerializer xml = new FastXmlSerializer();          xml.setOutput(out, "utf-8");          xml.startDocument("utf-8", true); diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java index 6a1e97a51453..a68f9d385ca5 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java @@ -196,11 +196,7 @@ final class UsageStatsXmlV1 {                  event.mNotificationChannelId = (channelId != null) ? channelId.intern() : null;                  break;          } - -        if (statsOut.events == null) { -            statsOut.events = new EventList(); -        } -        statsOut.events.insert(event); +        statsOut.addEvent(event);      }      private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats, diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 9b194e9ec638..1a8aba085d24 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -176,12 +176,8 @@ class UserUsageStatsService {                      currentDailyStats.activeConfiguration, newFullConfig);          } -        // Add the event to the daily list. -        if (currentDailyStats.events == null) { -            currentDailyStats.events = new EventList(); -        }          if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) { -            currentDailyStats.events.insert(event); +            currentDailyStats.addEvent(event);          }          boolean incrementAppLaunch = false; diff --git a/startop/tools/view_compiler/Android.bp b/startop/tools/view_compiler/Android.bp new file mode 100644 index 000000000000..c3e91849e636 --- /dev/null +++ b/startop/tools/view_compiler/Android.bp @@ -0,0 +1,49 @@ +// +// 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. +// + +cc_library_host_static { +    name: "libviewcompiler", +    srcs: [ +        "java_lang_builder.cc", +        "util.cc", +    ], +    static_libs: [ +        "libbase" +    ] +} + +cc_binary_host { +    name: "viewcompiler", +    srcs: [ +        "main.cc", +    ], +    static_libs: [ +        "libbase", +        "libtinyxml2", +        "libgflags", +        "libviewcompiler", +    ], +} + +cc_test_host { +    name: "view-compiler-tests", +    srcs: [ +        "util_test.cc", +    ], +    static_libs: [ +        "libviewcompiler", +    ] +} diff --git a/startop/tools/view_compiler/README.md b/startop/tools/view_compiler/README.md new file mode 100644 index 000000000000..56595016cbb9 --- /dev/null +++ b/startop/tools/view_compiler/README.md @@ -0,0 +1,25 @@ +# View Compiler + +This directory contains an experimental compiler for layout files. + +It will take a layout XML file and produce a CompiledLayout.java file with a +specialized layout inflation function. + +To use it, let's assume you had a layout in `my_layout.xml` and your app was in +the Java language package `com.example.myapp`. Run the following command: + +    viewcompiler my_layout.xml --package com.example.myapp --out CompiledView.java + +This will produce a `CompiledView.java`, which can then be compiled into your +Android app. Then to use it, in places where you would have inflated +`R.layouts.my_layout`, instead call `CompiledView.inflate`. + +Precompiling views like this generally improves the time needed to inflate them. + +This tool is still in its early stages and has a number of limitations. +* Currently only one layout can be compiled at a time. +* `merge` and `include` nodes are not supported. +* View compilation is a manual process that requires code changes in the +  application. +* This only works for apps that do not use a custom layout inflater. +* Other limitations yet to be discovered. diff --git a/startop/tools/view_compiler/TEST_MAPPING b/startop/tools/view_compiler/TEST_MAPPING new file mode 100644 index 000000000000..cc4b17a7a65a --- /dev/null +++ b/startop/tools/view_compiler/TEST_MAPPING @@ -0,0 +1,7 @@ +{ +  "presubmit": [ +    { +      "name": "view-compiler-tests" +    } +  ] +} diff --git a/startop/tools/view_compiler/java_lang_builder.cc b/startop/tools/view_compiler/java_lang_builder.cc new file mode 100644 index 000000000000..0b8754fc7096 --- /dev/null +++ b/startop/tools/view_compiler/java_lang_builder.cc @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#include "java_lang_builder.h" + +#include "android-base/stringprintf.h" + +using android::base::StringPrintf; +using std::string; + +void JavaLangViewBuilder::Start() const { +  out_ << StringPrintf("package %s;\n", package_.c_str()) +       << "import android.content.Context;\n" +          "import android.content.res.Resources;\n" +          "import android.content.res.XmlResourceParser;\n" +          "import android.util.AttributeSet;\n" +          "import android.util.Xml;\n" +          "import android.view.*;\n" +          "import android.widget.*;\n" +          "\n" +          "public final class CompiledView {\n" +          "\n" +          "static <T extends View> T createView(Context context, AttributeSet attrs, View parent, " +          "String name, LayoutInflater.Factory factory, LayoutInflater.Factory2 factory2) {" +          "\n" +          "  if (factory2 != null) {\n" +          "    return (T)factory2.onCreateView(parent, name, context, attrs);\n" +          "  } else if (factory != null) {\n" +          "    return (T)factory.onCreateView(name, context, attrs);\n" +          "  }\n" +          // TODO: find a way to call the private factory +          "  return null;\n" +          "}\n" +          "\n" +          "  public static View inflate(Context context) {\n" +          "    try {\n" +          "      LayoutInflater inflater = LayoutInflater.from(context);\n" +          "      LayoutInflater.Factory factory = inflater.getFactory();\n" +          "      LayoutInflater.Factory2 factory2 = inflater.getFactory2();\n" +          "      Resources res = context.getResources();\n" +       << StringPrintf("      XmlResourceParser xml = res.getLayout(%s.R.layout.%s);\n", +                       package_.c_str(), +                       layout_name_.c_str()) +       << "      AttributeSet attrs = Xml.asAttributeSet(xml);\n" +          // The Java-language XmlPullParser needs a call to next to find the start document tag. +          "      xml.next(); // start document\n"; +} + +void JavaLangViewBuilder::Finish() const { +  out_ << "    } catch (Exception e) {\n" +          "      return null;\n" +          "    }\n"  // end try +          "  }\n"    // end inflate +          "}\n";     // end CompiledView +} + +void JavaLangViewBuilder::StartView(const string& class_name) { +  const string view_var = MakeVar("view"); +  const string layout_var = MakeVar("layout"); +  std::string parent = "null"; +  if (!view_stack_.empty()) { +    const StackEntry& parent_entry = view_stack_.back(); +    parent = parent_entry.view_var; +  } +  out_ << "      xml.next(); // <" << class_name << ">\n" +       << StringPrintf("      %s %s = createView(context, attrs, %s, \"%s\", factory, factory2);\n", +                       class_name.c_str(), +                       view_var.c_str(), +                       parent.c_str(), +                       class_name.c_str()) +       << StringPrintf("      if (%s == null) %s = new %s(context, attrs);\n", +                       view_var.c_str(), +                       view_var.c_str(), +                       class_name.c_str()); +  if (!view_stack_.empty()) { +    out_ << StringPrintf("      ViewGroup.LayoutParams %s = %s.generateLayoutParams(attrs);\n", +                         layout_var.c_str(), +                         parent.c_str()); +  } +  view_stack_.push_back({class_name, view_var, layout_var}); +} + +void JavaLangViewBuilder::FinishView() { +  const StackEntry var = view_stack_.back(); +  view_stack_.pop_back(); +  if (!view_stack_.empty()) { +    const string& parent = view_stack_.back().view_var; +    out_ << StringPrintf("      xml.next(); // </%s>\n", var.class_name.c_str()) +         << StringPrintf("      %s.addView(%s, %s);\n", +                         parent.c_str(), +                         var.view_var.c_str(), +                         var.layout_params_var.c_str()); +  } else { +    out_ << StringPrintf("      return %s;\n", var.view_var.c_str()); +  } +} + +const std::string JavaLangViewBuilder::MakeVar(std::string prefix) { +  std::stringstream v; +  v << prefix << view_id_++; +  return v.str(); +} diff --git a/startop/tools/view_compiler/java_lang_builder.h b/startop/tools/view_compiler/java_lang_builder.h new file mode 100644 index 000000000000..c8d20b23cd13 --- /dev/null +++ b/startop/tools/view_compiler/java_lang_builder.h @@ -0,0 +1,65 @@ +/* + * 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. + */ +#ifndef JAVA_LANG_BUILDER_H_ +#define JAVA_LANG_BUILDER_H_ + +#include <iostream> +#include <sstream> +#include <vector> + +// Build Java language code to instantiate views. +// +// This has a very small interface to make it easier to generate additional +// backends, such as a direct-to-DEX version. +class JavaLangViewBuilder { + public: +  JavaLangViewBuilder(std::string package, std::string layout_name, std::ostream& out = std::cout) +      : package_(package), layout_name_(layout_name), out_(out) {} + +  // Begin generating a class. Adds the package boilerplate, etc. +  void Start() const; +  // Finish generating a class, closing off any open curly braces, etc. +  void Finish() const; + +  // Begin creating a view (i.e. process the opening tag) +  void StartView(const std::string& class_name); +  // Finish a view, after all of its child nodes have been processed. +  void FinishView(); + + private: +  const std::string MakeVar(std::string prefix); + +  std::string const package_; +  std::string const layout_name_; + +  std::ostream& out_; + +  size_t view_id_ = 0; + +  struct StackEntry { +      // The class name for this view object +      const std::string class_name; + +      // The variable name that is holding the view object +      const std::string view_var; + +      // The variable name that holds the object's layout parameters +      const std::string layout_params_var; +  }; +  std::vector<StackEntry> view_stack_; +}; + +#endif  // JAVA_LANG_BUILDER_H_ diff --git a/startop/tools/view_compiler/main.cc b/startop/tools/view_compiler/main.cc new file mode 100644 index 000000000000..0ad7e24feb3b --- /dev/null +++ b/startop/tools/view_compiler/main.cc @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include "gflags/gflags.h" + +#include "java_lang_builder.h" +#include "util.h" + +#include "tinyxml2.h" + +#include <fstream> +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +using namespace tinyxml2; +using std::string; + +constexpr char kStdoutFilename[]{"stdout"}; + +DEFINE_string(package, "", "The package name for the generated class (required)"); +DEFINE_string(out, kStdoutFilename, "Where to write the generated class"); + +namespace { +class ViewCompilerXmlVisitor : public XMLVisitor { + public: +  ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {} + +  bool VisitEnter(const XMLDocument& /*doc*/) override { +    builder_->Start(); +    return true; +  } + +  bool VisitExit(const XMLDocument& /*doc*/) override { +    builder_->Finish(); +    return true; +  } + +  bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override { +    builder_->StartView(element.Name()); +    return true; +  } + +  bool VisitExit(const XMLElement& /*element*/) override { +    builder_->FinishView(); +    return true; +  } + + private: +  JavaLangViewBuilder* builder_; +}; +}  // end namespace + +int main(int argc, char** argv) { +  constexpr size_t kProgramName = 0; +  constexpr size_t kFileNameParam = 1; +  constexpr size_t kNumRequiredArgs = 2; + +  gflags::SetUsageMessage( +      "Compile XML layout files into equivalent Java language code\n" +      "\n" +      "  example usage:  viewcompiler layout.xml --package com.example.androidapp"); +  gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true); + +  gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package"); +  if (argc != kNumRequiredArgs || cmd.is_default) { +    gflags::ShowUsageWithFlags(argv[kProgramName]); +    return 1; +  } + +  const char* const filename = argv[kFileNameParam]; +  const string layout_name = FindLayoutNameFromFilename(filename); + +  // We want to generate Java language code to inflate exactly this layout. This means +  // generating code to walk the resource XML too. + +  XMLDocument xml; +  xml.LoadFile(filename); + +  std::ofstream outfile; +  if (FLAGS_out != kStdoutFilename) { +    outfile.open(FLAGS_out); +  } +  JavaLangViewBuilder builder{ +      FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile}; + +  ViewCompilerXmlVisitor visitor{&builder}; +  xml.Accept(&visitor); + +  return 0; +}
\ No newline at end of file diff --git a/startop/tools/view_compiler/util.cc b/startop/tools/view_compiler/util.cc new file mode 100644 index 000000000000..69df41dff3d7 --- /dev/null +++ b/startop/tools/view_compiler/util.cc @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include "util.h" + +using std::string; + +// TODO: see if we can borrow this from somewhere else, like aapt2. +string FindLayoutNameFromFilename(const string& filename) { +  size_t start = filename.rfind("/"); +  if (start == string::npos) { +    start = 0; +  } else { +    start++;  // advance past '/' character +  } +  size_t end = filename.find(".", start); + +  return filename.substr(start, end - start); +} diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/startop/tools/view_compiler/util.h index 5d1985123b32..03e093920bfa 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java +++ b/startop/tools/view_compiler/util.h @@ -1,5 +1,5 @@  /* - * Copyright (C) 2016 The Android Open Source Project + * 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. @@ -11,15 +11,13 @@   * 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 + * limitations under the License.   */ +#ifndef UTIL_H_ +#define UTIL_H_ -package com.android.systemui.stackdivider.events; +#include <string> -import com.android.systemui.recents.events.EventBus; +std::string FindLayoutNameFromFilename(const std::string& filename); -/** - * Sent when the divider is being draged either manually or by an animation. - */ -public class StartedDragingEvent extends EventBus.Event { -} +#endif  // UTIL_H_ diff --git a/startop/tools/view_compiler/util_test.cc b/startop/tools/view_compiler/util_test.cc new file mode 100644 index 000000000000..d1540d3a6e43 --- /dev/null +++ b/startop/tools/view_compiler/util_test.cc @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include "util.h" + +#include "gtest/gtest.h" + +using std::string; + +TEST(UtilTest, FindLayoutNameFromFilename) { +  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("foo/bar.xml")); +  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("bar.xml")); +  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("./foo/bar.xml")); +  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("/foo/bar.xml")); +} diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 26bd4a106ca6..08bc9bcc4003 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -141,6 +141,8 @@ public final class Call {       * The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to       * Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_REQUEST_HANDOVER =              "android.telecom.event.REQUEST_HANDOVER"; @@ -149,6 +151,8 @@ public final class Call {       * Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event.  Specifies the       * {@link PhoneAccountHandle} to which a call should be handed over to.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE =              "android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE"; @@ -161,6 +165,8 @@ public final class Call {       * {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and       * {@link VideoProfile#STATE_TX_ENABLED}.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EXTRA_HANDOVER_VIDEO_STATE =              "android.telecom.extra.HANDOVER_VIDEO_STATE"; @@ -176,6 +182,8 @@ public final class Call {       * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}       * is called to initate the handover.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS"; @@ -186,6 +194,8 @@ public final class Call {       * <p>       * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_HANDOVER_COMPLETE =              "android.telecom.event.HANDOVER_COMPLETE"; @@ -198,6 +208,8 @@ public final class Call {       * <p>       * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED =              "android.telecom.event.HANDOVER_SOURCE_DISCONNECTED"; @@ -209,6 +221,8 @@ public final class Call {       * <p>       * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_HANDOVER_FAILED =              "android.telecom.event.HANDOVER_FAILED"; diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index d49469233752..34603a3f056a 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -594,6 +594,8 @@ public abstract class Connection extends Conferenceable {       * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has       * successfully completed.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_HANDOVER_COMPLETE =              "android.telecom.event.HANDOVER_COMPLETE"; @@ -603,6 +605,8 @@ public abstract class Connection extends Conferenceable {       * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed       * to complete.       * @hide +     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated +     * APIs instead.       */      public static final String EVENT_HANDOVER_FAILED =              "android.telecom.event.HANDOVER_FAILED"; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 995418ee706c..57b652e4cc59 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -271,6 +271,14 @@ public class CarrierConfigManager {              KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";      /** +     * Do only allow auto selection in Advanced Network Settings when in home network. +     * Manual selection is allowed when in roaming network. +     * @hide +     */ +    public static final String +            KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; + +    /**       * Control whether users receive a simplified network settings UI and improved network       * selection.       */ @@ -2181,6 +2189,7 @@ public class CarrierConfigManager {          sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);          sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false);          sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false); +        sDefaults.putBoolean(KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false);          sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false);          sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false); diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 8e99518d78b8..5e4518f67538 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -32,7 +32,11 @@ import android.os.Parcelable;  /**   * Represents the neighboring cell information, including   * Received Signal Strength and Cell ID location. + * + * @deprecated This class should not be used by anyone targeting SDK level 29 (Q) or higher. + *      Instead callers should use {@Link android.telephony.CellInfo}.   */ +@Deprecated  public class NeighboringCellInfo implements Parcelable  {      /** diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java index 7c7d7a0397ad..202da6817cb5 100644 --- a/telephony/java/android/telephony/NetworkScan.java +++ b/telephony/java/android/telephony/NetworkScan.java @@ -16,11 +16,10 @@  package android.telephony; +import android.annotation.IntDef;  import android.content.Context;  import android.os.RemoteException;  import android.os.ServiceManager; -import android.annotation.IntDef; -import android.util.Log;  import com.android.internal.telephony.ITelephony; @@ -113,6 +112,8 @@ public class NetworkScan {          }          try {              telephony.stopNetworkScan(mSubId, mScanId); +        } catch (IllegalArgumentException ex) { +            Rlog.d(TAG,  "stopNetworkScan - no active scan for ScanID=" + mScanId);          } catch (RemoteException ex) {              Rlog.e(TAG, "stopNetworkScan  RemoteException", ex);          } catch (RuntimeException ex) { diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 498be968265f..3ea018af97cf 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -281,6 +281,16 @@ public class PhoneStateListener {       */      public static final int LISTEN_PHONE_CAPABILITY_CHANGE                 = 0x00200000; +    /** +     *  Listen for changes to preferred data subId. +     *  See {@link SubscriptionManager#setPreferredData(int)} +     *  for more details. +     * +     *  @see #onPreferredDataSubIdChanged +     *  @hide +     */ +    public static final int LISTEN_PREFERRED_DATA_SUBID_CHANGE              = 0x00400000; +      /*       * Subscription used to listen to the phone state changes       * @hide @@ -407,6 +417,9 @@ public class PhoneStateListener {                          PhoneStateListener.this.onPhoneCapabilityChanged(                                  (PhoneCapability) msg.obj);                          break; +                    case LISTEN_PREFERRED_DATA_SUBID_CHANGE: +                        PhoneStateListener.this.onPreferredDataSubIdChanged((int) msg.obj); +                        break;                  }              }          }; @@ -647,6 +660,18 @@ public class PhoneStateListener {      }      /** +     * Callback invoked when preferred data subId changes. Requires +     * the READ_PRIVILEGED_PHONE_STATE permission. +     * @param subId the new preferred data subId. If it's INVALID_SUBSCRIPTION_ID, +     *              it means it's unset and defaultDataSub is used to determine which +     *              modem is preferred. +     * @hide +     */ +    public void onPreferredDataSubIdChanged(int subId) { +        // default implementation empty +    } + +    /**       * Callback invoked when telephony has received notice from a carrier       * app that a network action that could result in connectivity loss       * has been requested by an app using @@ -777,6 +802,11 @@ public class PhoneStateListener {          public void onPhoneCapabilityChanged(PhoneCapability capability) {              send(LISTEN_PHONE_CAPABILITY_CHANGE, 0, 0, capability);          } + +        public void onPreferredDataSubIdChanged(int subId) { +            send(LISTEN_PREFERRED_DATA_SUBID_CHANGE, 0, 0, subId); +        } +      }      /** diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 777b850bc9c5..cc143d63d624 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1852,6 +1852,19 @@ public class SubscriptionManager {      }      /** +     * Checks if the supplied subscription ID corresponds to an active subscription. +     * +     * @param subscriptionId the subscription ID. +     * @return {@code true} if the supplied subscription ID corresponds to an active subscription; +     * {@code false} if it does not correspond to an active subscription; or throw a +     * SecurityException if the caller hasn't got the right permission. +     */ +    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) +    public boolean isActiveSubscriptionId(int subscriptionId) { +        return isActiveSubId(subscriptionId); +    } + +    /**       * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription       * and the SIM providing the subscription is present in a slot and in "LOADED" state.       * @hide @@ -1861,7 +1874,7 @@ public class SubscriptionManager {          try {              ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));              if (iSub != null) { -                return iSub.isActiveSubId(subId); +                return iSub.isActiveSubId(subId, mContext.getOpPackageName());              }          } catch (RemoteException ex) {          } @@ -2140,9 +2153,15 @@ public class SubscriptionManager {      /**       * Set preferred default data. -     * Set on which slot default data will be on. +     * Set on which slot most cellular data will be on. +     * It's also usually what we set up internet connection on. +     * +     * PreferredData overwrites user setting of default data subscription. And it's used +     * by AlternativeNetworkAccessService or carrier apps to switch primary and CBRS +     * subscription dynamically in multi-SIM devices.       * -     * @param slotId which slot is preferred to for cellular data. +     * @param slotId which slot is preferred to for cellular data. If it's INVALID, it means +     *               it's unset and defaultDataSubId is used to determine which modem is preferred.       * @hide       *       */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d58b932f2851..ea9ac39c8111 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,6 +16,8 @@  package android.telephony; +import static android.content.Context.TELECOM_SERVICE; +  import static com.android.internal.util.Preconditions.checkNotNull;  import android.annotation.IntDef; @@ -1201,6 +1203,15 @@ public class TelephonyManager {              "android.intent.action.DATA_STALL_DETECTED";      /** +     * A service action that identifies a {@link android.app.SmsAppService} subclass in the +     * AndroidManifest.xml. +     * +     * <p>See {@link android.app.SmsAppService} for the details. +     */ +    @SdkConstant(SdkConstantType.SERVICE_ACTION) +    public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE"; + +    /**       * An int extra used with {@link #ACTION_DATA_STALL_DETECTED} to indicate the       * action associated with the data stall recovery.       * @@ -1579,6 +1590,7 @@ public class TelephonyManager {       *       * @return List of NeighboringCellInfo or null if info unavailable.       * +     * @removed       * @deprecated Use {@link #getAllCellInfo} which returns a superset of the information       *             from NeighboringCellInfo, including LTE cell information.       */ @@ -4372,7 +4384,7 @@ public class TelephonyManager {      * @hide      */      private ITelecomService getTelecomService() { -        return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE)); +        return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));      }      private ITelephonyRegistry getTelephonyRegistry() { @@ -5402,7 +5414,19 @@ public class TelephonyManager {          }      } -    // ICC SIM Application Types +    /** +     * UICC SIM Application Types +     * @hide +     */ +    @IntDef(prefix = { "APPTYPE_" }, value = { +            APPTYPE_SIM, +            APPTYPE_USIM, +            APPTYPE_RUIM, +            APPTYPE_CSIM, +            APPTYPE_ISIM +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface UiccAppType{}      /** UICC application type is SIM */      public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;      /** UICC application type is USIM */ @@ -5413,6 +5437,7 @@ public class TelephonyManager {      public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;      /** UICC application type is ISIM */      public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM; +      // authContext (parameter P2) when doing UICC challenge,      // per 3GPP TS 31.102 (Section 7.1.2)      /** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */ @@ -5679,6 +5704,202 @@ public class TelephonyManager {          }      } +    /** @hide */ +    @IntDef(prefix = { "NETWORK_MODE_" }, value = { +            NETWORK_MODE_WCDMA_PREF, +            NETWORK_MODE_GSM_ONLY, +            NETWORK_MODE_WCDMA_ONLY, +            NETWORK_MODE_GSM_UMTS, +            NETWORK_MODE_CDMA_EVDO, +            NETWORK_MODE_CDMA_NO_EVDO, +            NETWORK_MODE_EVDO_NO_CDMA, +            NETWORK_MODE_GLOBAL, +            NETWORK_MODE_LTE_CDMA_EVDO, +            NETWORK_MODE_LTE_GSM_WCDMA, +            NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA, +            NETWORK_MODE_LTE_ONLY, +            NETWORK_MODE_LTE_WCDMA, +            NETWORK_MODE_TDSCDMA_ONLY, +            NETWORK_MODE_TDSCDMA_WCDMA, +            NETWORK_MODE_LTE_TDSCDMA, +            NETWORK_MODE_TDSCDMA_GSM, +            NETWORK_MODE_LTE_TDSCDMA_GSM, +            NETWORK_MODE_TDSCDMA_GSM_WCDMA, +            NETWORK_MODE_LTE_TDSCDMA_WCDMA, +            NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA, +            NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA, +            NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface PrefNetworkMode{} + +    /** +     * preferred network mode is GSM/WCDMA (WCDMA preferred). +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF; + +    /** +     * preferred network mode is GSM only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY; + +    /** +     * preferred network mode is WCDMA only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY; + +    /** +     * preferred network mode is GSM/WCDMA (auto mode, according to PRL). +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS; + +    /** +     * preferred network mode is CDMA and EvDo (auto mode, according to PRL). +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA; + +    /** +     * preferred network mode is CDMA only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO; + +    /** +     * preferred network mode is EvDo only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA; + +    /** +     * preferred network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL). +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL; + +    /** +     * preferred network mode is LTE, CDMA and EvDo. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO; + +    /** +     * preferred network mode is LTE, GSM/WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA; + +    /** +     * preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = +            RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA; + +    /** +     * preferred network mode is LTE Only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY; + +    /** +     * preferred network mode is LTE/WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA; + +    /** +     * preferred network mode is TD-SCDMA only. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY; + +    /** +     * preferred network mode is TD-SCDMA and WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA; + +    /** +     * preferred network mode is TD-SCDMA and LTE. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA; + +    /** +     * preferred network mode is TD-SCDMA and GSM. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM; + +    /** +     * preferred network mode is TD-SCDMA,GSM and LTE. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = +            RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM; + +    /** +     * preferred network mode is TD-SCDMA, GSM/WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = +            RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA; + +    /** +     * preferred network mode is TD-SCDMA, WCDMA and LTE. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = +            RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA; + +    /** +     * preferred network mode is TD-SCDMA, GSM/WCDMA and LTE. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = +            RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA; + +    /** +     * preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = +            RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; +    /** +     * preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo. +     * @hide +     */ +    @SystemApi +    public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = +            RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; +      /**       * Get the preferred network type.       * Used for device configuration by some CDMA operators. @@ -5687,11 +5908,12 @@ public class TelephonyManager {       * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling       * app has carrier privileges (see {@link #hasCarrierPrivileges}).       * -     * @return the preferred network type, defined in RILConstants.java. +     * @return the preferred network type.       * @hide       */ -    @UnsupportedAppUsage -    public int getPreferredNetworkType(int subId) { +    @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE)) +    @SystemApi +    public @PrefNetworkMode int getPreferredNetworkType(int subId) {          try {              ITelephony telephony = getITelephony();              if (telephony != null) @@ -6273,7 +6495,7 @@ public class TelephonyManager {      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#endCall()} instead. +     * @removed Use {@link android.telecom.TelecomManager#endCall()} instead.       * @hide       * @removed       */ @@ -6285,7 +6507,7 @@ public class TelephonyManager {      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#acceptRingingCall} instead +     * @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead       * @hide       * @removed       */ @@ -6293,26 +6515,22 @@ public class TelephonyManager {      @SystemApi      @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)      public void answerRingingCall() { - +        // No-op      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#silenceRinger} instead +     * @removed Use {@link android.telecom.TelecomManager#silenceRinger} instead       * @hide       */      @Deprecated      @SystemApi      @SuppressLint("Doclava125")      public void silenceRinger() { -        try { -            getTelecomService().silenceRinger(getOpPackageName()); -        } catch (RemoteException e) { -            Log.e(TAG, "Error calling ITelecomService#silenceRinger", e); -        } +        // No-op      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead +     * @removed Use {@link android.telecom.TelecomManager#isInCall} instead       * @hide       */      @Deprecated @@ -6322,18 +6540,11 @@ public class TelephonyManager {              android.Manifest.permission.READ_PHONE_STATE      })      public boolean isOffhook() { -        try { -            ITelephony telephony = getITelephony(); -            if (telephony != null) -                return telephony.isOffhook(getOpPackageName()); -        } catch (RemoteException e) { -            Log.e(TAG, "Error calling ITelephony#isOffhook", e); -        }          return false;      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead +     * @removed Use {@link android.telecom.TelecomManager#isRinging} instead       * @hide       */      @Deprecated @@ -6343,18 +6554,11 @@ public class TelephonyManager {              android.Manifest.permission.READ_PHONE_STATE      })      public boolean isRinging() { -        try { -            ITelephony telephony = getITelephony(); -            if (telephony != null) -                return telephony.isRinging(getOpPackageName()); -        } catch (RemoteException e) { -            Log.e(TAG, "Error calling ITelephony#isRinging", e); -        }          return false;      }      /** -     * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead +     * @removed Use {@link android.telecom.TelecomManager#isInCall} instead       * @hide       */      @Deprecated @@ -6364,13 +6568,6 @@ public class TelephonyManager {              android.Manifest.permission.READ_PHONE_STATE      })      public boolean isIdle() { -        try { -            ITelephony telephony = getITelephony(); -            if (telephony != null) -                return telephony.isIdle(getOpPackageName()); -        } catch (RemoteException e) { -            Log.e(TAG, "Error calling ITelephony#isIdle", e); -        }          return true;      } @@ -7856,26 +8053,23 @@ public class TelephonyManager {      }      /** -     * Return the application ID for the app type like {@link APPTYPE_CSIM}. -     * -     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission +     * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}. +     * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220 +     * <p>Requires Permission: +     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}       * -     * @param appType the uicc app type like {@link APPTYPE_CSIM} -     * @return Application ID for specificied app type or null if no uicc or error. +     * @param appType the uicc app type. +     * @return Application ID for specified app type or {@code null} if no uicc or error.       * @hide       */ -    public String getAidForAppType(int appType) { +    @SystemApi +    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) +    public String getAidForAppType(@UiccAppType int appType) {          return getAidForAppType(getSubId(), appType);      }      /** -     * Return the application ID for the app type like {@link APPTYPE_CSIM}. -     * -     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission -     * -     * @param subId the subscription ID that this request applies to. -     * @param appType the uicc app type, like {@link APPTYPE_CSIM} -     * @return Application ID for specificied app type or null if no uicc or error. +     * same as {@link #getAidForAppType(int)}       * @hide       */      public String getAidForAppType(int subId, int appType) { diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 1ebb6976b45e..38a1bc73c94d 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -52,5 +52,6 @@ oneway interface IPhoneStateListener {      void onCarrierNetworkChange(in boolean active);      void onUserMobileDataStateChanged(in boolean enabled);      void onPhoneCapabilityChanged(in PhoneCapability capability); +    void onPreferredDataSubIdChanged(in int subId);  } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 6521f0b41cb2..0ccd748c31df 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -232,5 +232,5 @@ interface ISub {       */      int getSimStateForSlotIndex(int slotIndex); -    boolean isActiveSubId(int subId); +    boolean isActiveSubId(int subId, String callingPackage);  } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index e1c770c8deec..ca2bcff2f4cd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -75,116 +75,6 @@ interface ITelephony {      void call(String callingPackage, String number);      /** -     * End call if there is a call in progress, otherwise does nothing. -     * -     * @return whether it hung up -     */ -    boolean endCall(); - -    /** -     * End call on particular subId or go to the Home screen -     * @param subId user preferred subId. -     * @return whether it hung up -     */ -    boolean endCallForSubscriber(int subId); - -    /** -     * Answer the currently-ringing call. -     * -     * If there's already a current active call, that call will be -     * automatically put on hold.  If both lines are currently in use, the -     * current active call will be ended. -     * -     * TODO: provide a flag to let the caller specify what policy to use -     * if both lines are in use.  (The current behavior is hardwired to -     * "answer incoming, end ongoing", which is how the CALL button -     * is specced to behave.) -     * -     * TODO: this should be a oneway call (especially since it's called -     * directly from the key queue thread). -     */ -    void answerRingingCall(); - -    /** -     * Answer the currently-ringing call on particular subId . -     * -     * If there's already a current active call, that call will be -     * automatically put on hold.  If both lines are currently in use, the -     * current active call will be ended. -     * -     * TODO: provide a flag to let the caller specify what policy to use -     * if both lines are in use.  (The current behavior is hardwired to -     * "answer incoming, end ongoing", which is how the CALL button -     * is specced to behave.) -     * -     * TODO: this should be a oneway call (especially since it's called -     * directly from the key queue thread). -     */ -    void answerRingingCallForSubscriber(int subId); - -    /** -     * Silence the ringer if an incoming call is currently ringing. -     * (If vibrating, stop the vibrator also.) -     * -     * It's safe to call this if the ringer has already been silenced, or -     * even if there's no incoming call.  (If so, this method will do nothing.) -     * -     * TODO: this should be a oneway call too (see above). -     *       (Actually *all* the methods here that return void can -     *       probably be oneway.) -     */ -    void silenceRinger(); - -    /** -     * Check if we are in either an active or holding call -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is OFFHOOK. -     */ -    boolean isOffhook(String callingPackage); - -    /** -     * Check if a particular subId has an active or holding call -     * -     * @param subId user preferred subId. -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is OFFHOOK. -     */ -    boolean isOffhookForSubscriber(int subId, String callingPackage); - -    /** -     * Check if an incoming phone call is ringing or call waiting -     * on a particular subId. -     * -     * @param subId user preferred subId. -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is RINGING. -     */ -    boolean isRingingForSubscriber(int subId, String callingPackage); - -    /** -     * Check if an incoming phone call is ringing or call waiting. -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is RINGING. -     */ -    boolean isRinging(String callingPackage); - -    /** -     * Check if the phone is idle. -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is IDLE. -     */ -    boolean isIdle(String callingPackage); - -    /** -     * Check if the phone is idle on a particular subId. -     * -     * @param subId user preferred subId. -     * @param callingPackage the name of the package making the call. -     * @return true if the phone state is IDLE. -     */ -    boolean isIdleForSubscriber(int subId, String callingPackage); - -    /**       * Check to see if the radio is on or not.       * @param callingPackage the name of the package making the call.       * @return returns true if the radio is on. diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 43d56b39e0c4..c03065c34ca8 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -79,4 +79,5 @@ interface ITelephonyRegistry {      void notifyCarrierNetworkChange(in boolean active);      void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);      void notifyPhoneCapabilityChanged(in PhoneCapability capability); +    void notifyPreferredDataSubIdChanged(int preferredSubId);  } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index f9de776f9a7b..21f3b92c6c4f 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -176,6 +176,10 @@ public class PhoneConstants {      // FIXME: This is used to pass a subId via intents, we need to look at its usage, which is      // FIXME: extensive, and see if this should be an array of all active subId's or ...? +    /** +     * @Deprecated use {@link android.telephony.SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX} +     * instead. +     */      public static final String SUBSCRIPTION_KEY  = "subscription";      public static final String SUB_SETTING  = "subSettings"; diff --git a/test-base/Android.bp b/test-base/Android.bp index 0b8a02a815d9..4d765d3e5f3f 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -37,7 +37,8 @@ java_sdk_library {          "junit.framework",      ], -    droiddoc_options: ["stubsourceonly"], +    droiddoc_options: ["-stubsourceonly"], +    metalava_enabled: false,      compile_dex: true,  } diff --git a/test-mock/Android.bp b/test-mock/Android.bp index 5eba01779f46..37158e5fe0b9 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -26,5 +26,6 @@ java_sdk_library {      ],      srcs_lib_whitelist_pkgs: ["android"], +    metalava_enabled: false,      compile_dex: true,  } diff --git a/test-runner/Android.bp b/test-runner/Android.bp index ea615b920df6..0a0d50cc330c 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -40,7 +40,8 @@ java_sdk_library {          "junit.textui",      ], -    droiddoc_options: ["stubsourceonly"], +    droiddoc_options: ["-stubsourceonly"], +    metalava_enabled: false,      compile_dex: true  } diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 4a6fe49f2676..976848c60dc7 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -106,9 +106,8 @@ public class AppLaunch extends InstrumentationTestCase {      private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";      private static final String APP_LAUNCH_CMD = "am start -W -n";      private static final String SUCCESS_MESSAGE = "Status: ok"; -    private static final String WARNING_MESSAGE = "Warning:"; +    private static final String TOTAL_TIME_MESSAGE = "TotalTime:";      private static final String COMPILE_SUCCESS = "Success"; -    private static final String THIS_TIME = "ThisTime:";      private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";      private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";      private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION"; @@ -247,8 +246,14 @@ public class AppLaunch extends InstrumentationTestCase {                      mIterationCycle = false;                      // In the "applaunch.txt" file, trail launches is referenced using                      // "TRIAL_LAUNCH" -                    String appPkgName = mNameToIntent.get(launch.getApp()) -                        .getComponent().getPackageName(); +                    Intent startIntent = mNameToIntent.get(launch.getApp()); +                    if (startIntent == null) { +                        Log.w(TAG, "App does not exist: " + launch.getApp()); +                        mResult.putString(mNameToResultKey.get(launch.getApp()), +                            "App does not exist"); +                        continue; +                    } +                    String appPkgName = startIntent.getComponent().getPackageName();                      if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {                          assertTrue(String.format("Not able to compile the app : %s", appPkgName),                                compileApp(VERIFY_FILTER, appPkgName)); @@ -808,15 +813,13 @@ public class AppLaunch extends InstrumentationTestCase {              String launchTime = "-1";              String cpuCycles = "-1";              String majorFaults = "-1"; -            boolean coldLaunchSuccess = false; -            boolean hotLaunchSuccess = false; +            boolean launchSuccess = false;              try {                  InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());                  /* SAMPLE OUTPUT : Cold launch                  Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }                  Status: ok                  Activity: com.google.android.calculator/com.android.calculator2.Calculator -                ThisTime: 357                  TotalTime: 357                  WaitTime: 377                  Complete*/ @@ -825,7 +828,6 @@ public class AppLaunch extends InstrumentationTestCase {                  Warning: Activity not started, its current task has been brought to the front                  Status: ok                  Activity: com.google.android.calculator/com.android.calculator2.CalculatorGoogle -                ThisTime: 60                  TotalTime: 60                  WaitTime: 67                  Complete*/ @@ -836,54 +838,37 @@ public class AppLaunch extends InstrumentationTestCase {                  Total test time,1.462129,seconds,*/                  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(                          inputStream)); -                String line = null; -                int lineCount = 1; +                String line;                  mBufferedWriter.newLine();                  mBufferedWriter.write(headerInfo);                  mBufferedWriter.newLine();                  while ((line = bufferedReader.readLine()) != null) { -                    if (lineCount == 2 && line.startsWith(SUCCESS_MESSAGE)) { -                        coldLaunchSuccess = true; +                    mBufferedWriter.write(line); +                    mBufferedWriter.newLine(); +                    if (line.startsWith(SUCCESS_MESSAGE)) { +                        launchSuccess = true;                      } -                    if (lineCount == 2 && line.startsWith(WARNING_MESSAGE)) { -                        hotLaunchSuccess = true; +                    if (!launchSuccess) { +                        continue;                      }                      // Parse TotalTime which is the launch time -                    if (coldLaunchSuccess && lineCount == 5) { -                        String launchSplit[] = line.split(":"); -                        launchTime = launchSplit[1].trim(); -                    } -                    if (hotLaunchSuccess && lineCount == 6) { +                    if (line.startsWith(TOTAL_TIME_MESSAGE)) {                          String launchSplit[] = line.split(":");                          launchTime = launchSplit[1].trim();                      }                      if (mSimplePerfAppOnly) { -                        // Parse simpleperf output. -                        if ((lineCount == 9 && coldLaunchSuccess) -                                || (lineCount == 10 && hotLaunchSuccess)) { -                            if (!line.contains("cpu-cycles")) { -                                Log.e(TAG, "Error in simpleperf output"); -                            } else { -                                cpuCycles = line.split(",")[0].trim(); -                            } -                        } else if ((lineCount == 10 && coldLaunchSuccess) -                                || (lineCount == 11 && hotLaunchSuccess)) { -                            if (!line.contains("major-faults")) { -                                Log.e(TAG, "Error in simpleperf output"); -                            } else { -                                majorFaults = line.split(",")[0].trim(); -                            } +                        if (line.contains(",cpu-cycles,")) { +                            cpuCycles = line.split(",")[0].trim(); +                        } else if (line.contains(",major-faults,")) { +                            majorFaults = line.split(",")[0].trim();                          }                      } -                    mBufferedWriter.write(line); -                    mBufferedWriter.newLine(); -                    lineCount++;                  }                  mBufferedWriter.flush();                  inputStream.close();              } catch (IOException e) { -                Log.w(TAG, "Error writing the launch file", e); +                Log.w(TAG, "Error parsing launch time and writing to file", e);              }              return new AppLaunchResult(launchTime, cpuCycles, majorFaults);          } diff --git a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java index ae011a0316aa..c86f06eb88e4 100644 --- a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java +++ b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java @@ -21,6 +21,7 @@ import com.android.tradefed.log.LogUtil.CLog;  import com.android.tradefed.result.ByteArrayInputStreamSource;  import com.android.tradefed.result.ITestInvocationListener;  import com.android.tradefed.result.LogDataType; +import com.android.tradefed.result.TestDescription;  import com.android.tradefed.testtype.IDeviceTest;  import com.android.tradefed.testtype.IRemoteTest; @@ -84,7 +85,10 @@ public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {          // showmap requires root, we enable it here for the rest of the test          mTestDevice.enableAdbRoot(); -        listener.testRunStarted(RUN_NAME, 0 /* testCount */); +        listener.testRunStarted(RUN_NAME, 1 /* testCount */); + +        TestDescription testDescription = new TestDescription(getClass().getName(), "run"); +        listener.testStarted(testDescription);          // process name -> list of pids with that name          Map<String, List<String>> nativeProcesses = collectNativeProcesses(); @@ -94,7 +98,8 @@ public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {          mNativeProcessToMemory.put(                  NUM_NATIVE_PROCESSES_KEY, Integer.toString(nativeProcesses.size())); -        listener.testRunEnded(0, mNativeProcessToMemory); +        listener.testEnded(testDescription, mNativeProcessToMemory); +        listener.testRunEnded(0, new HashMap<String, String>());      }      /** Samples memory of all processes and logs the memory use. */ diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk index e827ec20ae3e..43bf0243b55b 100644 --- a/tests/RemoteDisplayProvider/Android.mk +++ b/tests/RemoteDisplayProvider/Android.mk @@ -18,9 +18,9 @@ LOCAL_PATH := $(call my-dir)  include $(CLEAR_VARS)  LOCAL_PACKAGE_NAME := RemoteDisplayProviderTest  LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +LOCAL_SDK_VERSION := system_current  LOCAL_SRC_FILES := $(call all-java-files-under, src)  LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res -LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay.stubs +LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay  LOCAL_CERTIFICATE := platform  include $(BUILD_PACKAGE) diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java index 39ecb7e5a45e..122edbaf078c 100644 --- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java +++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java @@ -69,17 +69,12 @@ public class InetDiagSocketTest {      private ConnectivityManager mCm;      private Context mContext;      private final static int SOCKET_TIMEOUT_MS = 100; -    private boolean mInetDiagUdpEnabled;      @Before      public void setUp() throws Exception {          Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();          mContext = instrumentation.getTargetContext();          mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); -        int expectedUid = Process.myUid(); -        UdpConnection udp = new UdpConnection("127.0.0.1", "127.0.0.2"); -        int uid = mCm.getConnectionOwnerUid(udp.protocol, udp.local, udp.remote); -        mInetDiagUdpEnabled = (uid == expectedUid);      }      private class Connection { @@ -188,11 +183,6 @@ public class InetDiagSocketTest {          tcp.close();          /** -         * TODO: STOPSHIP: Always test for UDP, do not allow opt-out. -         */ -        if (!mInetDiagUdpEnabled) return; - -        /**           * For UDP connections, either a complete match {protocol, local, remote} or a           * partial match {protocol, local} should return a valid UID.           */ diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java index d46facfaba06..86048604e95f 100644 --- a/tests/net/java/android/net/util/SharedLogTest.java +++ b/tests/net/java/android/net/util/SharedLogTest.java @@ -44,6 +44,8 @@ public class SharedLogTest {          final SharedLog logLevel2a = logTop.forSubComponent("twoA");          final SharedLog logLevel2b = logTop.forSubComponent("twoB");          logLevel2b.e("2b or not 2b"); +        logLevel2b.e("No exception", null); +        logLevel2b.e("Wait, here's one", new Exception("Test"));          logLevel2a.w("second post?");          final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); @@ -54,6 +56,9 @@ public class SharedLogTest {          final String[] expected = {              " - MARK first post!",              " - [twoB] ERROR 2b or not 2b", +            " - [twoB] ERROR No exception", +            // No stacktrace in shared log, only in logcat +            " - [twoB] ERROR Wait, here's one: Test",              " - [twoA] WARN second post?",              " - still logging",              " - [twoA.three] 3 >> 2", diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e3db7e8a1354..1a053057540f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -79,6 +79,7 @@ import static org.mockito.Mockito.when;  import android.app.NotificationManager;  import android.app.PendingIntent;  import android.content.BroadcastReceiver; +import android.content.ContentProvider;  import android.content.ContentResolver;  import android.content.Context;  import android.content.Intent; @@ -248,7 +249,7 @@ public class ConnectivityServiceTest {          @Spy private Resources mResources;          private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>(); -        MockContext(Context base) { +        MockContext(Context base, ContentProvider settingsProvider) {              super(base);              mResources = spy(base.getResources()); @@ -260,7 +261,7 @@ public class ConnectivityServiceTest {                      });              mContentResolver = new MockContentResolver(); -            mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); +            mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);          }          @Override @@ -1048,7 +1049,9 @@ public class ConnectivityServiceTest {              Looper.prepare();          } -        mServiceContext = new MockContext(InstrumentationRegistry.getContext()); +        FakeSettingsProvider.clearSettingsProvider(); +        mServiceContext = new MockContext(InstrumentationRegistry.getContext(), +                new FakeSettingsProvider());          LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);          LocalServices.addService(                  NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); @@ -1086,6 +1089,7 @@ public class ConnectivityServiceTest {              mEthernetNetworkAgent.disconnect();              mEthernetNetworkAgent = null;          } +        FakeSettingsProvider.clearSettingsProvider();      }      private static int transportToLegacyType(int transport) { @@ -4532,4 +4536,78 @@ public class ConnectivityServiceTest {          mCellNetworkAgent.disconnect();          mCm.unregisterNetworkCallback(networkCallback);      } + +    @Test +    public void testDataActivityTracking() throws RemoteException { +        final TestNetworkCallback networkCallback = new TestNetworkCallback(); +        final NetworkRequest networkRequest = new NetworkRequest.Builder() +                .addCapability(NET_CAPABILITY_INTERNET) +                .build(); +        mCm.registerNetworkCallback(networkRequest, networkCallback); + +        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); +        final LinkProperties cellLp = new LinkProperties(); +        cellLp.setInterfaceName(MOBILE_IFNAME); +        mCellNetworkAgent.sendLinkProperties(cellLp); +        reset(mNetworkManagementService); +        mCellNetworkAgent.connect(true); +        networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); +        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(), +                eq(ConnectivityManager.TYPE_MOBILE)); + +        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); +        final LinkProperties wifiLp = new LinkProperties(); +        wifiLp.setInterfaceName(WIFI_IFNAME); +        mWiFiNetworkAgent.sendLinkProperties(wifiLp); + +        // Network switch +        reset(mNetworkManagementService); +        mWiFiNetworkAgent.connect(true); +        networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); +        networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); +        networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); +        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(), +                eq(ConnectivityManager.TYPE_WIFI)); +        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME)); + +        // Disconnect wifi and switch back to cell +        reset(mNetworkManagementService); +        mWiFiNetworkAgent.disconnect(); +        networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); +        assertNoCallbacks(networkCallback); +        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME)); +        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(), +                eq(ConnectivityManager.TYPE_MOBILE)); + +        // reconnect wifi +        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); +        wifiLp.setInterfaceName(WIFI_IFNAME); +        mWiFiNetworkAgent.sendLinkProperties(wifiLp); +        mWiFiNetworkAgent.connect(true); +        networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); +        networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); +        networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + +        // Disconnect cell +        reset(mNetworkManagementService); +        mCellNetworkAgent.disconnect(); +        networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); +        // LOST callback is triggered earlier than removing idle timer. Broadcast should also be +        // sent as network being switched. Ensure rule removal for cell will not be triggered +        // unexpectedly before network being removed. +        waitForIdle(); +        verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME)); +        verify(mNetworkManagementService, times(1)).removeNetwork( +                eq(mCellNetworkAgent.getNetwork().netId)); + +        // Disconnect wifi +        ConditionVariable cv = waitForConnectivityBroadcasts(1); +        reset(mNetworkManagementService); +        mWiFiNetworkAgent.disconnect(); +        waitFor(cv); +        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME)); + +        // Clean up +        mCm.unregisterNetworkCallback(networkCallback); +    }  } diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 40d5544dccd8..a6ed9f252008 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -33,6 +33,7 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;  import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;  import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;  import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;  import static org.junit.Assert.assertEquals;  import static org.junit.Assert.assertTrue; @@ -75,6 +76,8 @@ import android.net.NetworkRequest;  import android.net.NetworkState;  import android.net.NetworkUtils;  import android.net.RouteInfo; +import android.net.dhcp.DhcpServer; +import android.net.dhcp.DhcpServingParams;  import android.net.ip.IpServer;  import android.net.ip.RouterAdvertisementDaemon;  import android.net.util.InterfaceParams; @@ -85,6 +88,7 @@ import android.net.wifi.WifiManager;  import android.os.Bundle;  import android.os.Handler;  import android.os.INetworkManagementService; +import android.os.Looper;  import android.os.PersistableBundle;  import android.os.RemoteException;  import android.os.test.TestLooper; @@ -146,6 +150,7 @@ public class TetheringTest {      @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;      @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;      @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon; +    @Mock private DhcpServer mDhcpServer;      @Mock private INetd mNetd;      private final MockTetheringDependencies mTetheringDependencies = @@ -240,6 +245,12 @@ public class TetheringTest {                  public INetd getNetdService() {                      return mNetd;                  } + +                @Override +                public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, +                        DhcpServingParams params, SharedLog log) { +                    return mDhcpServer; +                }              };          } @@ -333,6 +344,7 @@ public class TetheringTest {          mServiceContext = new MockContext(mContext);          mContentResolver = new MockContentResolver(mServiceContext);          mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); +        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);          mIntents = new Vector<>();          mBroadcastReceiver = new BroadcastReceiver() {              @Override @@ -343,12 +355,16 @@ public class TetheringTest {          mServiceContext.registerReceiver(mBroadcastReceiver,                  new IntentFilter(ACTION_TETHER_STATE_CHANGED));          mTetheringDependencies.reset(); -        mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager, -                                   mLooper.getLooper(), mSystemProperties, -                                   mTetheringDependencies); +        mTethering = makeTethering();          verify(mNMService).registerTetheringStatsProvider(any(), anyString());      } +    private Tethering makeTethering() { +        return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager, +                mLooper.getLooper(), mSystemProperties, +                mTetheringDependencies); +    } +      @After      public void tearDown() {          mServiceContext.unregisterReceiver(mBroadcastReceiver); @@ -597,6 +613,18 @@ public class TetheringTest {          sendIPv6TetherUpdates(upstreamState);          verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull()); +        verify(mDhcpServer, times(1)).start(); +    } + +    @Test +    public void workingMobileUsbTethering_IPv4LegacyDhcp() { +        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); +        mTethering = makeTethering(); +        final NetworkState upstreamState = buildMobileIPv4UpstreamState(); +        runUsbTethering(upstreamState); +        sendIPv6TetherUpdates(upstreamState); + +        verify(mDhcpServer, never()).start();      }      @Test @@ -620,6 +648,7 @@ public class TetheringTest {          verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);          verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);          verify(mRouterAdvertisementDaemon, times(1)).start(); +        verify(mDhcpServer, times(1)).start();          sendIPv6TetherUpdates(upstreamState);          verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -633,6 +662,7 @@ public class TetheringTest {          verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);          verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); +        verify(mDhcpServer, times(1)).start();          verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);          verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,                  TEST_XLAT_MOBILE_IFNAME); @@ -649,6 +679,7 @@ public class TetheringTest {          runUsbTethering(upstreamState);          verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); +        verify(mDhcpServer, times(1)).start();          verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);          // Then 464xlat comes up @@ -671,6 +702,8 @@ public class TetheringTest {          // Forwarding was not re-added for v6 (still times(1))          verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);          verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); +        // DHCP not restarted on downstream (still times(1)) +        verify(mDhcpServer, times(1)).start();      }      @Test diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index bb312309b34f..521778484d91 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -225,13 +225,4 @@ public class TetheringConfigurationTest {          final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);          assertFalse(cfg.enableLegacyDhcpServer);      } - -    @Test -    public void testNewDhcpServerDefault() { -        Settings.Global.putString(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, null); - -        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog); -        // TODO: change to false when new server is promoted to default -        assertTrue(cfg.enableLegacyDhcpServer); -    }  } diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h index f71955247d78..b46a50398217 100644 --- a/tools/aapt2/ConfigDescription.h +++ b/tools/aapt2/ConfigDescription.h @@ -53,11 +53,11 @@ struct ConfigDescription : public android::ResTable_config {    ConfigDescription();    ConfigDescription(const android::ResTable_config& o);  // NOLINT(implicit)    ConfigDescription(const ConfigDescription& o); -  ConfigDescription(ConfigDescription&& o); +  ConfigDescription(ConfigDescription&& o) noexcept;    ConfigDescription& operator=(const android::ResTable_config& o);    ConfigDescription& operator=(const ConfigDescription& o); -  ConfigDescription& operator=(ConfigDescription&& o); +  ConfigDescription& operator=(ConfigDescription&& o) noexcept;    ConfigDescription CopyWithoutSdkVersion() const; @@ -124,7 +124,7 @@ inline ConfigDescription::ConfigDescription(const ConfigDescription& o) {    *static_cast<android::ResTable_config*>(this) = o;  } -inline ConfigDescription::ConfigDescription(ConfigDescription&& o) { +inline ConfigDescription::ConfigDescription(ConfigDescription&& o) noexcept {    *this = o;  } @@ -141,7 +141,7 @@ inline ConfigDescription& ConfigDescription::operator=(    return *this;  } -inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) { +inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) noexcept {    *this = o;    return *this;  } diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp index c0eaa8e08418..7872738320c3 100644 --- a/tools/aapt2/io/FileStream_test.cpp +++ b/tools/aapt2/io/FileStream_test.cpp @@ -41,46 +41,46 @@ TEST(FileInputStreamTest, NextAndBackup) {    ASSERT_FALSE(in.HadError());    EXPECT_THAT(in.ByteCount(), Eq(0u)); -  const char* buffer; +  const void* buffer;    size_t size; -  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError(); +  ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError();    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    EXPECT_THAT(in.ByteCount(), Eq(10u)); -  EXPECT_THAT(StringPiece(buffer, size), Eq("this is a ")); +  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a ")); -  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); +  ASSERT_TRUE(in.Next(&buffer, &size));    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    EXPECT_THAT(in.ByteCount(), Eq(20u)); -  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin")); +  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));    in.BackUp(5u);    EXPECT_THAT(in.ByteCount(), Eq(15u)); -  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); +  ASSERT_TRUE(in.Next(&buffer, &size));    ASSERT_THAT(size, Eq(5u));    ASSERT_THAT(buffer, NotNull());    ASSERT_THAT(in.ByteCount(), Eq(20u)); -  EXPECT_THAT(StringPiece(buffer, size), Eq("strin")); +  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin"));    // Backup 1 more than possible. Should clamp.    in.BackUp(11u);    EXPECT_THAT(in.ByteCount(), Eq(10u)); -  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); +  ASSERT_TRUE(in.Next(&buffer, &size));    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    ASSERT_THAT(in.ByteCount(), Eq(20u)); -  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin")); +  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin")); -  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); +  ASSERT_TRUE(in.Next(&buffer, &size));    ASSERT_THAT(size, Eq(1u));    ASSERT_THAT(buffer, NotNull());    ASSERT_THAT(in.ByteCount(), Eq(21u)); -  EXPECT_THAT(StringPiece(buffer, size), Eq("g")); +  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g")); -  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); +  EXPECT_FALSE(in.Next(&buffer, &size));    EXPECT_FALSE(in.HadError());  } @@ -93,25 +93,25 @@ TEST(FileOutputStreamTest, NextAndBackup) {    ASSERT_FALSE(out.HadError());    EXPECT_THAT(out.ByteCount(), Eq(0u)); -  char* buffer; +  void* buffer;    size_t size; -  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); +  ASSERT_TRUE(out.Next(&buffer, &size));    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    EXPECT_THAT(out.ByteCount(), Eq(10u)); -  memcpy(buffer, input.c_str(), size); +  memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size); -  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); +  ASSERT_TRUE(out.Next(&buffer, &size));    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    EXPECT_THAT(out.ByteCount(), Eq(20u)); -  memcpy(buffer, input.c_str() + 10u, size); +  memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size); -  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); +  ASSERT_TRUE(out.Next(&buffer, &size));    ASSERT_THAT(size, Eq(10u));    ASSERT_THAT(buffer, NotNull());    EXPECT_THAT(out.ByteCount(), Eq(30u)); -  buffer[0] = input[20u]; +  reinterpret_cast<char*>(buffer)[0] = input[20u];    out.BackUp(size - 1);    EXPECT_THAT(out.ByteCount(), Eq(21u)); diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp index be67c9c8c03c..10e504ec0752 100644 --- a/tools/aapt2/java/ManifestClassGenerator.cpp +++ b/tools/aapt2/java/ManifestClassGenerator.cpp @@ -26,21 +26,20 @@  #include "util/Maybe.h"  #include "xml/XmlDom.h" -using ::android::StringPiece;  using ::aapt::text::IsJavaIdentifier;  namespace aapt { -static Maybe<StringPiece> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source, +static Maybe<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,                                                  const std::string& value) { -  StringPiece result = value; +  std::string result = value;    size_t pos = value.rfind('.');    if (pos != std::string::npos) {      result = result.substr(pos + 1);    }    // Normalize only the java identifier, leave the original value unchanged. -  if (result.contains("-")) { +  if (result.find("-") != std::string::npos) {      result = JavaClassGenerator::TransformToFieldName(result);    } @@ -64,7 +63,7 @@ static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element*      return false;    } -  Maybe<StringPiece> result = +  Maybe<std::string> result =        ExtractJavaIdentifier(diag, source.WithLine(el->line_number), attr->value);    if (!result) {      return false; diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h index 30452552888e..d4b3abce68a7 100644 --- a/tools/aapt2/util/BigBuffer.h +++ b/tools/aapt2/util/BigBuffer.h @@ -68,7 +68,7 @@ class BigBuffer {     */    explicit BigBuffer(size_t block_size); -  BigBuffer(BigBuffer&& rhs); +  BigBuffer(BigBuffer&& rhs) noexcept;    /**     * Number of occupied bytes in all the allocated blocks. @@ -136,7 +136,7 @@ class BigBuffer {  inline BigBuffer::BigBuffer(size_t block_size)      : block_size_(block_size), size_(0) {} -inline BigBuffer::BigBuffer(BigBuffer&& rhs) +inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept      : block_size_(rhs.block_size_),        size_(rhs.size_),        blocks_(std::move(rhs.blocks_)) {} diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h index 59858e492c4c..1727b18e4106 100644 --- a/tools/aapt2/util/ImmutableMap.h +++ b/tools/aapt2/util/ImmutableMap.h @@ -32,8 +32,8 @@ class ImmutableMap {    using const_iterator =        typename std::vector<std::pair<TKey, TValue>>::const_iterator; -  ImmutableMap(ImmutableMap&&) = default; -  ImmutableMap& operator=(ImmutableMap&&) = default; +  ImmutableMap(ImmutableMap&&) noexcept = default; +  ImmutableMap& operator=(ImmutableMap&&) noexcept = default;    static ImmutableMap<TKey, TValue> CreatePreSorted(        std::initializer_list<std::pair<TKey, TValue>> list) { diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h index 9a82418e0a5a..031276c8b885 100644 --- a/tools/aapt2/util/Maybe.h +++ b/tools/aapt2/util/Maybe.h @@ -46,7 +46,7 @@ class Maybe {    template <typename U>    Maybe(const Maybe<U>& rhs);  // NOLINT(implicit) -  Maybe(Maybe&& rhs); +  Maybe(Maybe&& rhs) noexcept;    template <typename U>    Maybe(Maybe<U>&& rhs);  // NOLINT(implicit) @@ -56,7 +56,7 @@ class Maybe {    template <typename U>    Maybe& operator=(const Maybe<U>& rhs); -  Maybe& operator=(Maybe&& rhs); +  Maybe& operator=(Maybe&& rhs) noexcept;    template <typename U>    Maybe& operator=(Maybe<U>&& rhs); @@ -134,7 +134,7 @@ Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) {  }  template <typename T> -Maybe<T>::Maybe(Maybe&& rhs) : nothing_(rhs.nothing_) { +Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) {    if (!rhs.nothing_) {      rhs.nothing_ = true; @@ -192,7 +192,7 @@ Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {  }  template <typename T> -inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) { +inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept {    // Delegate to the actual assignment.    return move(std::forward<Maybe<T>>(rhs));  } diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 934847f6eec2..91cd1cba964d 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -492,6 +492,7 @@ def verify_parcelable(clazz):  def verify_protected(clazz):      """Verify that no protected methods or fields are allowed."""      for m in clazz.methods: +        if m.name == "finalize": continue          if "protected" in m.split:              error(clazz, m, "M7", "Protected methods not allowed; must be public")      for f in clazz.fields: @@ -1025,6 +1026,10 @@ def verify_resource_names(clazz):      # Resources defined by files are foo_bar_baz      if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:          for f in clazz.fields: +            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue +            if f.name.startswith("config_"): +                error(clazz, f, None, "Expected config name to be config_fooBarBaz style") +              if re.match("[a-z1-9_]+$", f.name): continue              error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style") @@ -1361,6 +1366,60 @@ def verify_clone(clazz):              error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()") +def verify_pfd(clazz): +    """Verify that android APIs use PFD over FD.""" +    examine = clazz.ctors + clazz.methods +    for m in examine: +        if m.typ == "java.io.FileDescriptor": +            error(clazz, m, "FW11", "Must use ParcelFileDescriptor") +        if m.typ == "int": +            if "Fd" in m.name or "FD" in m.name or "FileDescriptor" in m.name: +                error(clazz, m, "FW11", "Must use ParcelFileDescriptor") +        for arg in m.args: +            if arg == "java.io.FileDescriptor": +                error(clazz, m, "FW11", "Must use ParcelFileDescriptor") + +    for f in clazz.fields: +        if f.typ == "java.io.FileDescriptor": +            error(clazz, f, "FW11", "Must use ParcelFileDescriptor") + + +def verify_numbers(clazz): +    """Discourage small numbers types like short and byte.""" + +    discouraged = ["short","byte"] + +    for c in clazz.ctors: +        for arg in c.args: +            if arg in discouraged: +                warn(clazz, c, "FW12", "Should avoid odd sized primitives; use int instead") + +    for f in clazz.fields: +        if f.typ in discouraged: +            warn(clazz, f, "FW12", "Should avoid odd sized primitives; use int instead") + +    for m in clazz.methods: +        if m.typ in discouraged: +            warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") +        for arg in m.args: +            if arg in discouraged: +                warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") + + +def verify_singleton(clazz): +    """Catch singleton objects with constructors.""" + +    singleton = False +    for m in clazz.methods: +        if m.name.startswith("get") and m.name.endswith("Instance") and " static " in m.raw: +            singleton = True + +    if singleton: +        for c in clazz.ctors: +            error(clazz, c, None, "Singleton classes should use getInstance() methods") + + +  def is_interesting(clazz):      """Test if given class is interesting from an Android PoV.""" @@ -1431,6 +1490,9 @@ def examine_clazz(clazz):      verify_tense(clazz)      verify_icu(clazz)      verify_clone(clazz) +    verify_pfd(clazz) +    verify_numbers(clazz) +    verify_singleton(clazz)  def examine_stream(stream): diff --git a/tools/fonts/add_additional_fonts.py b/tools/fonts/add_additional_fonts.py deleted file mode 100644 index bf4af2b1c56e..000000000000 --- a/tools/fonts/add_additional_fonts.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -# 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. -# - -import sys - -def main(argv): -    original_file = 'frameworks/base/data/fonts/fonts.xml' - -    if len(argv) == 3: -        output_file_path = argv[1] -        override_file_path = argv[2] -    else: -        raise ValueError("Wrong number of arguments %s" % len(argv)) - -    fallbackPlaceholderFound = False -    with open(original_file, 'r') as input_file: -        with open(output_file_path, 'w') as output_file: -            for line in input_file: -                # If we've found the spot to add additional fonts, add them. -                if line.strip() == '<!-- fallback fonts -->': -                    fallbackPlaceholderFound = True -                    with open(override_file_path) as override_file: -                        for override_line in override_file: -                            output_file.write(override_line) -                output_file.write(line) -    if not fallbackPlaceholderFound: -        raise ValueError('<!-- fallback fonts --> not found in source file: %s' % original_file) - -if __name__ == '__main__': -    main(sys.argv) diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 991547916919..56c842805190 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -234,9 +234,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,                      }                  }              } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { -                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " -                             "const std::map<int, char const*>& arg%d_2, " -                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); +                fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " +                             "const std::map<int, int64_t>& arg%d_2, " +                             "const std::map<int, char const*>& arg%d_3, " +                             "const std::map<int, float>& arg%d_4", +                             argIndex, argIndex, argIndex, argIndex);              } else {                  fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);              } @@ -302,6 +304,13 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,                      fprintf(out, "         event.end();\n");                      fprintf(out, "    }\n"); +                    fprintf(out, "    for (const auto& it : arg%d_4) {\n", argIndex); +                    fprintf(out, "         event.begin();\n"); +                    fprintf(out, "         event << it.first;\n"); +                    fprintf(out, "         event << it.second;\n"); +                    fprintf(out, "         event.end();\n"); +                    fprintf(out, "    }\n"); +                      fprintf(out, "    event.end();\n\n");              } else {                  if (*arg == JAVA_TYPE_STRING) { @@ -344,9 +353,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,                     }                 }             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { -                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " -                             "const std::map<int, char const*>& arg%d_2, " -                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); +                fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " +                             "const std::map<int, int64_t>& arg%d_2, " +                             "const std::map<int, char const*>& arg%d_3, " +                             "const std::map<int, float>& arg%d_4", +                             argIndex, argIndex, argIndex, argIndex);             } else {                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);             } @@ -374,7 +385,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,                     }                 }             } else  if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { -                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex); +                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", +                        argIndex, argIndex, argIndex, argIndex);             } else {                 fprintf(out, ", arg%d", argIndex);             } @@ -529,10 +541,14 @@ static void write_cpp_usage(                  }              }          } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { -            fprintf(out, ", const std::map<int, int64_t>& %s_int" +            fprintf(out, ", const std::map<int, int32_t>& %s_int" +                         ", const std::map<int, int64_t>& %s_long"                           ", const std::map<int, char const*>& %s_str"                           ", const std::map<int, float>& %s_float", -                         field->name.c_str(), field->name.c_str(), field->name.c_str()); +                         field->name.c_str(), +                         field->name.c_str(), +                         field->name.c_str(), +                         field->name.c_str());          } else {              fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());          } @@ -561,9 +577,11 @@ static void write_cpp_method_header(                      }                  }              } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { -                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " -                             "const std::map<int, char const*>& arg%d_2, " -                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); +                fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " +                             "const std::map<int, int64_t>& arg%d_2, " +                             "const std::map<int, char const*>& arg%d_3, " +                             "const std::map<int, float>& arg%d_4", +                             argIndex, argIndex, argIndex, argIndex);              } else {                  fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);              } @@ -976,6 +994,7 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att  }  static void write_key_value_map_jni(FILE* out) { +   fprintf(out, "    std::map<int, int32_t> int32_t_map;\n");     fprintf(out, "    std::map<int, int64_t> int64_t_map;\n");     fprintf(out, "    std::map<int, float> float_map;\n");     fprintf(out, "    std::map<int, char const*> string_map;\n\n"); @@ -989,9 +1008,11 @@ static void write_key_value_map_jni(FILE* out) {     fprintf(out, "    std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n"); +   fprintf(out, "    jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");     fprintf(out, "    jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");     fprintf(out, "    jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");     fprintf(out, "    jclass jstring_class = env->FindClass(\"java/lang/String\");\n"); +   fprintf(out, "    jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");     fprintf(out, "    jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");     fprintf(out, "    jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n"); @@ -1000,7 +1021,9 @@ static void write_key_value_map_jni(FILE* out) {     fprintf(out, "        jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");     fprintf(out, "        jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");     fprintf(out, "        if (jvalue_obj == NULL) { continue; }\n"); -   fprintf(out, "        if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n"); +   fprintf(out, "        if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n"); +   fprintf(out, "            int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n"); +   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");     fprintf(out, "            int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");     fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");     fprintf(out, "            float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n"); @@ -1129,7 +1152,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp                      }                  }              } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { -                fprintf(out, ", int64_t_map, string_map, float_map"); +                fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");              } else {                  const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";                  fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex); diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index ce8d71d7ed2a..58c130017024 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -332,9 +332,10 @@ public class WifiConfiguration implements Parcelable {      public String preSharedKey;      /** -     * Up to four WEP keys. Either an ASCII string enclosed in double -     * quotation marks (e.g., {@code "abcdef"}) or a string -     * of hex digits (e.g., {@code 0102030405}). +     * Four WEP keys. For each of the four values, provide either an ASCII +     * string enclosed in double quotation marks (e.g., {@code "abcdef"}), +     * a string of hex digits (e.g., {@code 0102030405}), or an empty string +     * (e.g., {@code ""}).       * <p/>       * When the value of one of these keys is read, the actual key is       * not returned, just a "*" if the key has a value, or the null diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 7a91347102fe..59ba8e7a6177 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1698,9 +1698,7 @@ public class WifiManager {       * @return the list of access points found in the most recent scan. An app must hold       * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or       * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission -     * in order to get valid results.  If there is a remote exception (e.g., either a communication -     * problem with the system service or an exception within the framework) an empty list will be -     * returned. +     * in order to get valid results.       */      public List<ScanResult> getScanResults() {          try {  |