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 { |