diff options
330 files changed, 11321 insertions, 7596 deletions
diff --git a/Android.bp b/Android.bp index 158644096a0d..07b301867129 100644 --- a/Android.bp +++ b/Android.bp @@ -495,6 +495,8 @@ java_library { "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl", "telephony/java/android/telephony/data/IDataService.aidl", "telephony/java/android/telephony/data/IDataServiceCallback.aidl", + "telephony/java/android/telephony/data/IQualifiedNetworksService.aidl", + "telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl", "telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl", "telephony/java/android/telephony/ims/aidl/IImsCapabilityCallback.aidl", "telephony/java/android/telephony/ims/aidl/IImsConfig.aidl", @@ -1524,6 +1526,10 @@ droiddoc { api_file: "api/current.txt", removed_api_file: "api/removed.txt", }, + last_released: { + api_file: ":last-released-public-api", + removed_api_file: "api/removed.txt", + }, }, } @@ -1544,6 +1550,10 @@ droiddoc { api_file: "api/system-current.txt", removed_api_file: "api/system-removed.txt", }, + last_released: { + api_file: ":last-released-system-api", + removed_api_file: "api/system-removed.txt", + }, }, } diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index ae42882f917a..de83f3e01074 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -15,3 +15,7 @@ api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREU strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT} hidden_api_txt_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} + +ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} + +owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$" diff --git a/api/current.txt b/api/current.txt index fc595ac49a2c..e9f57562fa3b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14726,6 +14726,22 @@ package android.graphics.drawable { method public void setColorFilter(android.graphics.ColorFilter); } + public class ColorStateListDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { + ctor public ColorStateListDrawable(); + ctor public ColorStateListDrawable(android.content.res.ColorStateList); + method public void clearAlpha(); + method public void draw(android.graphics.Canvas); + method public android.content.res.ColorStateList getColorStateList(); + method public int getOpacity(); + method public boolean hasFocusStateSpecified(); + method public void invalidateDrawable(android.graphics.drawable.Drawable); + method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); + method public void setAlpha(int); + method public void setColorFilter(android.graphics.ColorFilter); + method public void setColorStateList(android.content.res.ColorStateList); + method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); + } + public abstract class Drawable { ctor public Drawable(); method public void applyTheme(android.content.res.Resources.Theme); @@ -41948,9 +41964,10 @@ package android.telephony { field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool"; + field public static final java.lang.String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array"; field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; - field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; + field public static final deprecated java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool"; field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; @@ -53001,6 +53018,7 @@ package android.widget { method public int getWidth(); method public float getZoom(); method public void show(float, float); + method public void show(float, float, float, float); method public void update(); } diff --git a/api/system-current.txt b/api/system-current.txt index d9befc7eb87e..72cf0c71b167 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4725,6 +4725,7 @@ package android.service.notification { method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int); method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String); + method public void onNotificationsSeen(java.util.List<java.lang.String>); method public final void unsnoozeNotification(java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } @@ -4733,6 +4734,7 @@ package android.service.notification { ctor public NotificationStats(); ctor protected NotificationStats(android.os.Parcel); method public int describeContents(); + method public int getDismissalSentiment(); method public int getDismissalSurface(); method public boolean hasDirectReplied(); method public boolean hasExpanded(); @@ -4741,6 +4743,7 @@ package android.service.notification { method public boolean hasSnoozed(); method public boolean hasViewedSettings(); method public void setDirectReplied(); + method public void setDismissalSentiment(int); method public void setDismissalSurface(int); method public void setExpanded(); method public void setSeen(); @@ -4753,6 +4756,10 @@ package android.service.notification { field public static final int DISMISSAL_OTHER = 0; // 0x0 field public static final int DISMISSAL_PEEK = 1; // 0x1 field public static final int DISMISSAL_SHADE = 3; // 0x3 + field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0 + field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1 + field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2 + field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18 } public final class SnoozeCriterion implements android.os.Parcelable { @@ -5546,6 +5553,19 @@ package android.telephony.data { field public static final int RESULT_SUCCESS = 0; // 0x0 } + public abstract class QualifiedNetworksService extends android.app.Service { + ctor public QualifiedNetworksService(); + method public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int); + field public static final java.lang.String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService"; + } + + public abstract class QualifiedNetworksService.NetworkAvailabilityUpdater implements java.lang.AutoCloseable { + ctor public QualifiedNetworksService.NetworkAvailabilityUpdater(int); + method public abstract void close(); + method public final int getSlotIndex(); + method public final void updateQualifiedNetworkTypes(int, int[]); + } + } package android.telephony.euicc { @@ -6206,6 +6226,10 @@ package android.telephony.ims.feature { field public static final int STATE_UNAVAILABLE = 0; // 0x0 } + public static class ImsFeature.Capabilities { + field protected int mCapabilities; + } + protected static class ImsFeature.CapabilityCallbackProxy { method public void onChangeCapabilityConfigurationError(int, int, int); } diff --git a/api/test-current.txt b/api/test-current.txt index 1657de5624f3..f6cda32f4c9f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5,11 +5,11 @@ package android { field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; + field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION"; field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; + field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; - field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; - field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION"; } } @@ -28,11 +28,11 @@ package android.app { public class ActivityManager { method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int); method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName); + method public void forceStopPackage(java.lang.String); method public int getPackageImportance(java.lang.String); method public long getTotalRam(); method public int getUidImportance(int); method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); - method public void forceStopPackage(java.lang.String); method public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); } @@ -53,21 +53,21 @@ package android.app { } public class ActivityTaskManager { + method public java.lang.String listAllStacks(); + method public void moveTaskToStack(int, int, boolean); + method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect); method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException; method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException; + method public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect); method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException; + method public void resizeStack(int, android.graphics.Rect, boolean); + method public void resizeTask(int, android.graphics.Rect); method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException; - method public static boolean supportsMultiWindow(android.content.Context); - method public static boolean supportsSplitScreenMultiWindow(android.content.Context); - method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect); method public void startSystemLockTaskMode(int); method public void stopSystemLockTaskMode(); - method public void moveTaskToStack(int, int, boolean); - method public void resizeStack(int, android.graphics.Rect, boolean); - method public void resizeTask(int, android.graphics.Rect); - method public void resizeDockedStack(android.graphics.Rect,android.graphics.Rect); - method public java.lang.String listAllStacks(); + method public static boolean supportsMultiWindow(android.content.Context); + method public static boolean supportsSplitScreenMultiWindow(android.content.Context); field public static final int INVALID_STACK_ID = -1; // 0xffffffff field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1 field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0 @@ -1025,10 +1025,12 @@ package android.service.autofill { public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer { ctor public InternalSanitizer(); + method public abstract android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue); } public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { ctor public InternalTransformation(); + method public static boolean batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer, android.service.autofill.InternalTransformation>>); } public abstract class InternalValidator implements android.os.Parcelable android.service.autofill.Validator { @@ -1092,6 +1094,7 @@ package android.service.notification { method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String); + method public void onNotificationsSeen(java.util.List<java.lang.String>); method public final void unsnoozeNotification(java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } @@ -1104,6 +1107,7 @@ package android.service.notification { ctor public NotificationStats(); ctor protected NotificationStats(android.os.Parcel); method public int describeContents(); + method public int getDismissalSentiment(); method public int getDismissalSurface(); method public boolean hasDirectReplied(); method public boolean hasExpanded(); @@ -1112,6 +1116,7 @@ package android.service.notification { method public boolean hasSnoozed(); method public boolean hasViewedSettings(); method public void setDirectReplied(); + method public void setDismissalSentiment(int); method public void setDismissalSurface(int); method public void setExpanded(); method public void setSeen(); @@ -1124,6 +1129,10 @@ package android.service.notification { field public static final int DISMISSAL_OTHER = 0; // 0x0 field public static final int DISMISSAL_PEEK = 1; // 0x1 field public static final int DISMISSAL_SHADE = 3; // 0x3 + field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0 + field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1 + field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2 + field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18 } public final class SnoozeCriterion implements android.os.Parcelable { diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 043b7f90ced7..a826ec7c717e 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -845,6 +845,7 @@ public final class Bmgr { System.err.println(" bmgr fullbackup PACKAGE..."); System.err.println(" bmgr backupnow [--monitor|--monitor-verbose] --all|PACKAGE..."); System.err.println(" bmgr cancel backups"); + System.err.println(" bmgr init TRANSPORT..."); System.err.println(""); System.err.println("The 'backup' command schedules a backup pass for the named package."); System.err.println("Note that the backup pass will effectively be a no-op if the package"); @@ -902,7 +903,11 @@ public final class Bmgr { System.err.println("For each package it will run key/value or full data backup "); System.err.println("depending on the package's manifest declarations."); System.err.println("The data is sent via the currently active transport."); + System.err.println(""); System.err.println("The 'cancel backups' command cancels all running backups."); + System.err.println(""); + System.err.println("The 'init' command initializes the given transports, wiping all data"); + System.err.println("from their backing data stores."); } private static class BackupMonitor extends IBackupManagerMonitor.Stub { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 048fb43bfa3d..e915cc811676 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -302,6 +302,7 @@ status_t BootAnimation::readyToRun() { mHeight = h; mFlingerSurfaceControl = control; mFlingerSurface = s; + mTargetInset = -1; // If the device has encryption turned on or is in process // of being encrypted we show the encrypted boot animation. @@ -942,6 +943,7 @@ bool BootAnimation::playAnimation(const Animation& animation) if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawClock(animation.clockFont, part.clockPosX, part.clockPosY); } + handleViewport(frameDuration); eglSwapBuffers(mDisplay, mSurface); @@ -966,7 +968,7 @@ bool BootAnimation::playAnimation(const Animation& animation) usleep(part.pause * ns2us(frameDuration)); // For infinite parts, we've now played them at least once, so perhaps exit - if(exitPending() && !part.count) + if(exitPending() && !part.count && mCurrentInset >= mTargetInset) break; } @@ -986,6 +988,51 @@ bool BootAnimation::playAnimation(const Animation& animation) return true; } +void BootAnimation::handleViewport(nsecs_t timestep) { + if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) { + return; + } + if (mTargetInset < 0) { + // Poll the amount for the top display inset. This will return -1 until persistent properties + // have been loaded. + mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top", + -1 /* default */, -1 /* min */, mHeight / 2 /* max */); + } + if (mTargetInset <= 0) { + return; + } + + if (mCurrentInset < mTargetInset) { + // After the device boots, the inset will effectively be cropped away. We animate this here. + float fraction = static_cast<float>(mCurrentInset) / mTargetInset; + int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset; + + SurfaceComposerClient::Transaction() + .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight)) + .apply(); + } else { + // At the end of the animation, we switch to the viewport that DisplayManager will apply + // later. This changes the coordinate system, and means we must move the surface up by + // the inset amount. + sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + + Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset); + Rect displayRect(0, mTargetInset, mWidth, mHeight); + + SurfaceComposerClient::Transaction t; + t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset) + .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight)); + t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect); + t.apply(); + + mTargetInset = mCurrentInset = 0; + } + + int delta = timestep * mTargetInset / ms2ns(200); + mCurrentInset += delta; +} + void BootAnimation::releaseAnimation(Animation* animation) const { for (Vector<Animation::Part>::iterator it = animation->parts.begin(), diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index dffbfde649e0..498eebce5999 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -158,11 +158,15 @@ private: void checkExit(); + void handleViewport(nsecs_t timestep); + sp<SurfaceComposerClient> mSession; AssetManager mAssets; Texture mAndroid[2]; int mWidth; int mHeight; + int mCurrentInset; + int mTargetInset; bool mUseNpotTextures = false; EGLDisplay mDisplay; EGLDisplay mContext; diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index c37d0cfdba93..33f3917f05ad 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -50,7 +50,7 @@ const int FIELD_ID_ANOMALY_ALARM_STATS = 9; // const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp const int FIELD_ID_LOGGER_ERROR_STATS = 11; const int FIELD_ID_PERIODIC_ALARM_STATS = 12; -const int FIELD_ID_LOG_LOSS_STATS = 14; +// const int FIELD_ID_LOG_LOSS_STATS = 14; const int FIELD_ID_SYSTEM_SERVER_RESTART = 15; const int FIELD_ID_ATOM_STATS_TAG = 1; @@ -180,12 +180,12 @@ void StatsdStats::noteConfigReset(const ConfigKey& key) { noteConfigResetInternalLocked(key); } -void StatsdStats::noteLogLost(int64_t timestampNs, int32_t count) { +void StatsdStats::noteLogLost(int32_t wallClockTimeSec, int32_t count) { lock_guard<std::mutex> lock(mLock); - if (mLogLossTimestampNs.size() == kMaxLoggerErrors) { - mLogLossTimestampNs.pop_front(); + if (mLogLossStats.size() == kMaxLoggerErrors) { + mLogLossStats.pop_front(); } - mLogLossTimestampNs.push_back(std::make_pair(timestampNs, count)); + mLogLossStats.push_back(std::make_pair(wallClockTimeSec, count)); } void StatsdStats::noteBroadcastSent(const ConfigKey& key) { @@ -365,15 +365,6 @@ void StatsdStats::noteSystemServerRestart(int32_t timeSec) { mSystemServerRestartSec.push_back(timeSec); } -void StatsdStats::noteLoggerError(int error) { - lock_guard<std::mutex> lock(mLock); - // grows strictly one at a time. so it won't > kMaxLoggerErrors - if (mLoggerErrors.size() == kMaxLoggerErrors) { - mLoggerErrors.pop_front(); - } - mLoggerErrors.push_back(std::make_pair(getWallClockSec(), error)); -} - void StatsdStats::reset() { lock_guard<std::mutex> lock(mLock); resetInternalLocked(); @@ -386,9 +377,8 @@ void StatsdStats::resetInternalLocked() { std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); mAnomalyAlarmRegisteredStats = 0; mPeriodicAlarmRegisteredStats = 0; - mLoggerErrors.clear(); mSystemServerRestartSec.clear(); - mLogLossTimestampNs.clear(); + mLogLossStats.clear(); for (auto& config : mConfigStats) { config.second->broadcast_sent_time_sec.clear(); config.second->data_drop_time_sec.clear(); @@ -515,21 +505,13 @@ void StatsdStats::dumpStats(FILE* out) const { mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps, mUidMapStats.dropped_changes); - for (const auto& error : mLoggerErrors) { - time_t error_time = error.first; - struct tm* error_tm = localtime(&error_time); - char buffer[80]; - strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M%p\n", error_tm); - fprintf(out, "Logger error %d at %s\n", error.second, buffer); - } - for (const auto& restart : mSystemServerRestartSec) { fprintf(out, "System server restarts at %s(%lld)\n", buildTimeString(restart).c_str(), (long long)restart); } - for (const auto& loss : mLogLossTimestampNs) { - fprintf(out, "Log loss: %lld (elapsedRealtimeNs) - %d (count)\n", (long long)loss.first, + for (const auto& loss : mLogLossStats) { + fprintf(out, "Log loss: %lld (wall clock sec) - %d (count)\n", (long long)loss.first, loss.second); } } @@ -678,7 +660,10 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DELETED_APPS, mUidMapStats.deleted_apps); proto.end(uidMapToken); - for (const auto& error : mLoggerErrors) { + for (const auto& error : mLogLossStats) { + // The logger error stats are not used anymore since we move away from logd. + // Temporarily use this field to log the log loss timestamp and count + // TODO(b/80538532) Add a dedicated field in stats_log for this. uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_LOGGER_ERROR_STATS | FIELD_COUNT_REPEATED); proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_TIME, error.first); @@ -686,11 +671,6 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { proto.end(token); } - for (const auto& loss : mLogLossTimestampNs) { - proto.write(FIELD_TYPE_INT64 | FIELD_ID_LOG_LOSS_STATS | FIELD_COUNT_REPEATED, - (long long)loss.first); - } - for (const auto& restart : mSystemServerRestartSec) { proto.write(FIELD_TYPE_INT32 | FIELD_ID_SYSTEM_SERVER_RESTART | FIELD_COUNT_REPEATED, restart); diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index daea027e68f9..b5156dadade6 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -271,11 +271,6 @@ public: // Notify pull request for an atom served from cached data void notePullFromCache(int pullAtomId); - /** - * Records statsd met an error while reading from logd. - */ - void noteLoggerError(int error); - /* * Records when system server restarts. */ @@ -284,7 +279,7 @@ public: /** * Records statsd skipped an event. */ - void noteLogLost(int64_t timestamp, int32_t count); + void noteLogLost(int32_t wallClockTimeSec, int32_t count); /** * Reset the historical stats. Including all stats in icebox, and the tracked stats about @@ -338,11 +333,8 @@ private: // Maps PullAtomId to its stats. The size is capped by the puller atom counts. std::map<int, PulledAtomStats> mPulledAtomStats; - // Logd errors. Size capped by kMaxLoggerErrors. - std::list<const std::pair<int, int>> mLoggerErrors; - // Timestamps when we detect log loss, and the number of logs lost. - std::list<std::pair<int64_t, int32_t>> mLogLossTimestampNs; + std::list<std::pair<int32_t, int32_t>> mLogLossStats; std::list<int32_t> mSystemServerRestartSec; diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp index 4041da7b84d2..9b0691b6092d 100755 --- a/cmds/statsd/src/socket/StatsSocketListener.cpp +++ b/cmds/statsd/src/socket/StatsSocketListener.cpp @@ -111,7 +111,8 @@ bool StatsSocketListener::onDataAvailable(SocketClient* cli) { android_log_event_int_t* int_event = reinterpret_cast<android_log_event_int_t*>(ptr); if (int_event->header.tag == kLibLogTag && int_event->payload.type == EVENT_TYPE_INT) { ALOGE("Found dropped events: %d", int_event->payload.data); - StatsdStats::getInstance().noteLogLost(getElapsedRealtimeNs(), int_event->payload.data); + StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(), + int_event->payload.data); return true; } } diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index a78773692ef3..9ca0745c04f4 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -12204,11 +12204,11 @@ HPLorg/json/JSONStringer;->value(J)Lorg/json/JSONStringer; HPLorg/json/JSONStringer;->value(Z)Lorg/json/JSONStringer; HPLorg/json/JSONTokener;->syntaxError(Ljava/lang/String;)Lorg/json/JSONException; HPLorg/json/JSONTokener;->toString()Ljava/lang/String; -HPLorg/kxml2/io/KXmlSerializer;->getDepth()I -HPLorg/kxml2/io/KXmlSerializer;->getNamespace()Ljava/lang/String; -HPLorg/kxml2/io/KXmlSerializer;->getPrefix(Ljava/lang/String;ZZ)Ljava/lang/String; -HPLorg/kxml2/io/KXmlSerializer;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V -HPLorg/kxml2/io/KXmlSerializer;->text(Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +HPLcom/android/org/kxml2/io/KXmlSerializer;->getDepth()I +HPLcom/android/org/kxml2/io/KXmlSerializer;->getNamespace()Ljava/lang/String; +HPLcom/android/org/kxml2/io/KXmlSerializer;->getPrefix(Ljava/lang/String;ZZ)Ljava/lang/String; +HPLcom/android/org/kxml2/io/KXmlSerializer;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V +HPLcom/android/org/kxml2/io/KXmlSerializer;->text(Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; HPLorg/w3c/dom/NamedNodeMap;->getLength()I HPLorg/w3c/dom/NamedNodeMap;->getNamedItem(Ljava/lang/String;)Lorg/w3c/dom/Node; HPLorg/w3c/dom/NamedNodeMap;->getNamedItemNS(Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/Node; @@ -51896,7 +51896,7 @@ HSPLorg/apache/harmony/xml/dom/NodeListImpl;->item(I)Lorg/w3c/dom/Node; HSPLorg/apache/harmony/xml/dom/TextImpl;->getNodeType()S HSPLorg/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl;->newDocumentBuilder()Ljavax/xml/parsers/DocumentBuilder; HSPLorg/apache/harmony/xml/parsers/DocumentBuilderImpl;->appendText(Lorg/apache/harmony/xml/dom/DocumentImpl;Lorg/w3c/dom/Node;ILjava/lang/String;)V -HSPLorg/apache/harmony/xml/parsers/DocumentBuilderImpl;->parse(Lorg/kxml2/io/KXmlParser;Lorg/apache/harmony/xml/dom/DocumentImpl;Lorg/w3c/dom/Node;I)V +HSPLorg/apache/harmony/xml/parsers/DocumentBuilderImpl;->parse(Lcom/android/org/kxml2/io/KXmlParser;Lorg/apache/harmony/xml/dom/DocumentImpl;Lorg/w3c/dom/Node;I)V HSPLorg/apache/harmony/xml/parsers/DocumentBuilderImpl;->parse(Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document; HSPLorg/apache/harmony/xml/parsers/SAXParserFactoryImpl;->getFeature(Ljava/lang/String;)Z HSPLorg/apache/harmony/xml/parsers/SAXParserFactoryImpl;->isValidating()Z @@ -52176,64 +52176,64 @@ HSPLorg/json/JSONTokener;->readEscapeCharacter()C HSPLorg/json/JSONTokener;->readLiteral()Ljava/lang/Object; HSPLorg/json/JSONTokener;->readObject()Lorg/json/JSONObject; HSPLorg/json/JSONTokener;->skipToEndOfLine()V -HSPLorg/kxml2/io/KXmlParser$ValueContext;-><init>(Ljava/lang/String;I)V -HSPLorg/kxml2/io/KXmlParser;-><init>()V -HSPLorg/kxml2/io/KXmlParser;->adjustNsp()Z -HSPLorg/kxml2/io/KXmlParser;->close()V -HSPLorg/kxml2/io/KXmlParser;->fillBuffer(I)Z -HSPLorg/kxml2/io/KXmlParser;->getAttributeCount()I -HSPLorg/kxml2/io/KXmlParser;->getAttributeName(I)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getAttributeNamespace(I)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getAttributePrefix(I)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getAttributeType(I)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getAttributeValue(I)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getColumnNumber()I -HSPLorg/kxml2/io/KXmlParser;->getDepth()I -HSPLorg/kxml2/io/KXmlParser;->getEventType()I -HSPLorg/kxml2/io/KXmlParser;->getFeature(Ljava/lang/String;)Z -HSPLorg/kxml2/io/KXmlParser;->getLineNumber()I -HSPLorg/kxml2/io/KXmlParser;->getName()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getNamespace()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getNamespace(Ljava/lang/String;)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getNamespaceCount(I)I -HSPLorg/kxml2/io/KXmlParser;->getPositionDescription()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getPrefix()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getText()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->getTextCharacters([I)[C -HSPLorg/kxml2/io/KXmlParser;->next()I -HSPLorg/kxml2/io/KXmlParser;->next(Z)I -HSPLorg/kxml2/io/KXmlParser;->nextTag()I -HSPLorg/kxml2/io/KXmlParser;->nextText()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->nextToken()I -HSPLorg/kxml2/io/KXmlParser;->parseStartTag(ZZ)V -HSPLorg/kxml2/io/KXmlParser;->peekType(Z)I -HSPLorg/kxml2/io/KXmlParser;->read(C)V -HSPLorg/kxml2/io/KXmlParser;->read([C)V -HSPLorg/kxml2/io/KXmlParser;->readComment(Z)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->readEndTag()V -HSPLorg/kxml2/io/KXmlParser;->readEntity(Ljava/lang/StringBuilder;ZZLorg/kxml2/io/KXmlParser$ValueContext;)V -HSPLorg/kxml2/io/KXmlParser;->readName()Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->readUntil([CZ)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->readValue(CZZLorg/kxml2/io/KXmlParser$ValueContext;)Ljava/lang/String; -HSPLorg/kxml2/io/KXmlParser;->readXmlDeclaration()V -HSPLorg/kxml2/io/KXmlParser;->require(ILjava/lang/String;Ljava/lang/String;)V -HSPLorg/kxml2/io/KXmlParser;->setFeature(Ljava/lang/String;Z)V -HSPLorg/kxml2/io/KXmlParser;->setInput(Ljava/io/InputStream;Ljava/lang/String;)V -HSPLorg/kxml2/io/KXmlParser;->setInput(Ljava/io/Reader;)V -HSPLorg/kxml2/io/KXmlSerializer;-><init>()V -HSPLorg/kxml2/io/KXmlSerializer;->append(Ljava/lang/String;II)V -HSPLorg/kxml2/io/KXmlSerializer;->attribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; -HSPLorg/kxml2/io/KXmlSerializer;->check(Z)V -HSPLorg/kxml2/io/KXmlSerializer;->endDocument()V -HSPLorg/kxml2/io/KXmlSerializer;->endTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; -HSPLorg/kxml2/io/KXmlSerializer;->flush()V -HSPLorg/kxml2/io/KXmlSerializer;->setFeature(Ljava/lang/String;Z)V -HSPLorg/kxml2/io/KXmlSerializer;->setOutput(Ljava/io/OutputStream;Ljava/lang/String;)V -HSPLorg/kxml2/io/KXmlSerializer;->setOutput(Ljava/io/Writer;)V -HSPLorg/kxml2/io/KXmlSerializer;->startDocument(Ljava/lang/String;Ljava/lang/Boolean;)V -HSPLorg/kxml2/io/KXmlSerializer;->startTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; -HSPLorg/kxml2/io/KXmlSerializer;->writeEscaped(Ljava/lang/String;I)V +HSPLcom/android/org/kxml2/io/KXmlParser$ValueContext;-><init>(Ljava/lang/String;I)V +HSPLcom/android/org/kxml2/io/KXmlParser;-><init>()V +HSPLcom/android/org/kxml2/io/KXmlParser;->adjustNsp()Z +HSPLcom/android/org/kxml2/io/KXmlParser;->close()V +HSPLcom/android/org/kxml2/io/KXmlParser;->fillBuffer(I)Z +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeCount()I +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeName(I)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeNamespace(I)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributePrefix(I)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeType(I)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeValue(I)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getColumnNumber()I +HSPLcom/android/org/kxml2/io/KXmlParser;->getDepth()I +HSPLcom/android/org/kxml2/io/KXmlParser;->getEventType()I +HSPLcom/android/org/kxml2/io/KXmlParser;->getFeature(Ljava/lang/String;)Z +HSPLcom/android/org/kxml2/io/KXmlParser;->getLineNumber()I +HSPLcom/android/org/kxml2/io/KXmlParser;->getName()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getNamespace()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getNamespace(Ljava/lang/String;)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getNamespaceCount(I)I +HSPLcom/android/org/kxml2/io/KXmlParser;->getPositionDescription()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getPrefix()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getText()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->getTextCharacters([I)[C +HSPLcom/android/org/kxml2/io/KXmlParser;->next()I +HSPLcom/android/org/kxml2/io/KXmlParser;->next(Z)I +HSPLcom/android/org/kxml2/io/KXmlParser;->nextTag()I +HSPLcom/android/org/kxml2/io/KXmlParser;->nextText()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->nextToken()I +HSPLcom/android/org/kxml2/io/KXmlParser;->parseStartTag(ZZ)V +HSPLcom/android/org/kxml2/io/KXmlParser;->peekType(Z)I +HSPLcom/android/org/kxml2/io/KXmlParser;->read(C)V +HSPLcom/android/org/kxml2/io/KXmlParser;->read([C)V +HSPLcom/android/org/kxml2/io/KXmlParser;->readComment(Z)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->readEndTag()V +HSPLcom/android/org/kxml2/io/KXmlParser;->readEntity(Ljava/lang/StringBuilder;ZZLcom/android/org/kxml2/io/KXmlParser$ValueContext;)V +HSPLcom/android/org/kxml2/io/KXmlParser;->readName()Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->readUntil([CZ)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->readValue(CZZLcom/android/org/kxml2/io/KXmlParser$ValueContext;)Ljava/lang/String; +HSPLcom/android/org/kxml2/io/KXmlParser;->readXmlDeclaration()V +HSPLcom/android/org/kxml2/io/KXmlParser;->require(ILjava/lang/String;Ljava/lang/String;)V +HSPLcom/android/org/kxml2/io/KXmlParser;->setFeature(Ljava/lang/String;Z)V +HSPLcom/android/org/kxml2/io/KXmlParser;->setInput(Ljava/io/InputStream;Ljava/lang/String;)V +HSPLcom/android/org/kxml2/io/KXmlParser;->setInput(Ljava/io/Reader;)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;-><init>()V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->append(Ljava/lang/String;II)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->attribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +HSPLcom/android/org/kxml2/io/KXmlSerializer;->check(Z)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->endDocument()V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->endTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +HSPLcom/android/org/kxml2/io/KXmlSerializer;->flush()V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->setFeature(Ljava/lang/String;Z)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->setOutput(Ljava/io/OutputStream;Ljava/lang/String;)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->setOutput(Ljava/io/Writer;)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->startDocument(Ljava/lang/String;Ljava/lang/Boolean;)V +HSPLcom/android/org/kxml2/io/KXmlSerializer;->startTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +HSPLcom/android/org/kxml2/io/KXmlSerializer;->writeEscaped(Ljava/lang/String;I)V HSPLorg/w3c/dom/Attr;->getName()Ljava/lang/String; HSPLorg/w3c/dom/Attr;->getOwnerElement()Lorg/w3c/dom/Element; HSPLorg/w3c/dom/Attr;->getSchemaTypeInfo()Lorg/w3c/dom/TypeInfo; @@ -63397,9 +63397,9 @@ Lorg/json/JSONObject; Lorg/json/JSONStringer$Scope; Lorg/json/JSONStringer; Lorg/json/JSONTokener; -Lorg/kxml2/io/KXmlParser$ValueContext; -Lorg/kxml2/io/KXmlParser; -Lorg/kxml2/io/KXmlSerializer; +Lcom/android/org/kxml2/io/KXmlParser$ValueContext; +Lcom/android/org/kxml2/io/KXmlParser; +Lcom/android/org/kxml2/io/KXmlSerializer; Lorg/w3c/dom/CharacterData; Lorg/w3c/dom/DOMImplementation; Lorg/w3c/dom/Document; diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 3a96cd3f3eca..196f89cd69ee 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -455,59 +455,6 @@ Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landr Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V Landroid/hardware/biometrics/BiometricConstants;->BIOMETRIC_ERROR_VENDOR_BASE:I Landroid/hardware/biometrics/BiometricFingerprintConstants;->FINGERPRINT_ERROR_VENDOR_BASE:I -Landroid/hardware/camera2/CameraCharacteristics;->CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->CONTROL_MAX_REGIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->LED_AVAILABLE_LEDS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->LENS_INFO_SHADING_MAP_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->LOGICAL_MULTI_CAMERA_PHYSICAL_IDS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->QUIRKS_USE_PARTIAL_RESULT:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_CHARACTERISTICS_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_REQUEST_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_RESULT_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_SESSION_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_MAX_NUM_OUTPUT_STREAMS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_FORMATS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_JPEG_MIN_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_JPEG_SIZES:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_PROCESSED_SIZES:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; -Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_COORDINATES:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->REQUEST_ID:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_BLUE:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_GREEN:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_RED:Landroid/hardware/camera2/CaptureRequest$Key; -Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_COORDINATES:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->QUIRKS_PARTIAL_RESULT:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->REQUEST_FRAME_COUNT:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->REQUEST_ID:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_FACE_IDS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_FACE_LANDMARKS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_FACE_RECTANGLES:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_FACE_SCORES:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_LENS_SHADING_MAP:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_OIS_TIMESTAMPS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_OIS_X_SHIFTS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_OIS_Y_SHIFTS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_PREDICTED_COLOR_GAINS:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->STATISTICS_PREDICTED_COLOR_TRANSFORM:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->SYNC_FRAME_NUMBER:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_BLUE:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_GREEN:Landroid/hardware/camera2/CaptureResult$Key; -Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_RED:Landroid/hardware/camera2/CaptureResult$Key; Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager; Landroid/hardware/display/IDisplayManager;->getDisplayInfo(I)Landroid/view/DisplayInfo; Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -2480,7 +2427,6 @@ Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landr Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String; Lcom/android/internal/view/BaseIWindow;-><init>()V Lcom/android/internal/view/IInputMethod$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethod; -Lcom/android/internal/view/IInputMethod;->attachToken(Landroid/os/IBinder;)V Lcom/android/internal/view/IInputMethod;->bindInput(Landroid/view/inputmethod/InputBinding;)V Lcom/android/internal/view/IInputMethod;->hideSoftInput(ILandroid/os/ResultReceiver;)V Lcom/android/internal/view/IInputMethod;->setSessionEnabled(Lcom/android/internal/view/IInputMethodSession;Z)V @@ -2492,8 +2438,6 @@ Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/I Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List; Lcom/android/internal/view/IInputMethodManager$Stub;-><init>()V Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; -Lcom/android/internal/view/IInputMethodManager;->addClient(Lcom/android/internal/view/IInputMethodClient;Lcom/android/internal/view/IInputContext;II)V -Lcom/android/internal/view/IInputMethodManager;->removeClient(Lcom/android/internal/view/IInputMethodClient;)V Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession; Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings; Lcom/android/internal/widget/ILockSettings;->getBoolean(Ljava/lang/String;ZI)Z diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java index 05de3e8caa3f..fbba6dafde29 100644 --- a/core/java/android/annotation/UnsupportedAppUsage.java +++ b/core/java/android/annotation/UnsupportedAppUsage.java @@ -51,6 +51,39 @@ public @interface UnsupportedAppUsage { long trackingBug() default 0; /** + * Indicates that usage of this API is limited to apps based on their target SDK version. + * + * Access to the API is allowed if the targetSdkVersion in the apps manifest is no greater than + * this value. Access checks are performed at runtime. + * + * This is used to give app developers a grace period to migrate off a non-SDK interface. When + * making Android version N, existing APIs can have a maxTargetSdk of N-1 added to them. + * Developers must then migrate off the API when their app is updated in future, but it will + * continue working in the meantime. + * + * Possible values are: + * <ul> + * <li> + * {@link android.os.Build.VERSION_CODES#O} or {@link android.os.Build.VERSION_CODES#P}, + * to limit access to apps targeting these SDKs (or earlier). + * </li> + * <li> + * absent (default value) - All apps can access this API, but doing so may result in + * warnings in the log, UI warnings (on developer builds) and/or strictmode violations. + * The API is likely to be further restricted in future. + * </li> + * + * </ul> + * + * Note, if this is set to {@link android.os.Build.VERSION_CODES#O}, apps targeting O + * maintenance releases will also be allowed to use the API, and similarly for any future + * maintenance releases of P. + * + * @return The maximum value for an apps targetSdkVersion in order to access this API. + */ + int maxTargetSdk() default Integer.MAX_VALUE; + + /** * For debug use only. The expected dex signature to be generated for this API, used to verify * parts of the build process. * diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index a010c7238e3d..912070144986 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -149,6 +149,7 @@ import com.android.internal.os.RuntimeInit; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import com.android.org.conscrypt.OpenSSLSocketImpl; import com.android.org.conscrypt.TrustedCertificateStore; @@ -5324,6 +5325,16 @@ public final class ActivityThread extends ClientTransactionHandler { } } + /** + * Updates the application info. + * + * This only works in the system process. Must be called on the main thread. + */ + public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) { + Preconditions.checkState(mSystemThread, "Must only be called in the system process"); + handleApplicationInfoChanged(ai); + } + void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { // Updates triggered by package installation go through a package update // receiver. Here we try to capture ApplicationInfo changes that are diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 966f9025e8a3..d21f76d435e6 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -30,6 +30,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -270,7 +271,7 @@ public final class BluetoothA2dp implements BluetoothProfile { ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - mContext.getUser())) { + UserHandle.CURRENT_OR_SELF)) { Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent); return false; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a6b81b52633e..8c2b76f5dc34 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2250,6 +2250,7 @@ public class Intent implements Parcelable, Cloneable { * <p>Includes the following extras: * <ul> * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been suspended + * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been suspended * </ul> * * <p class="note">This is a protected intent that can only be sent @@ -2262,6 +2263,7 @@ public class Intent implements Parcelable, Cloneable { * <p>Includes the following extras: * <ul> * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been unsuspended + * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been unsuspended * </ul> * * <p class="note">This is a protected intent that can only be sent diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 83e287aecb41..b7a53520f060 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -615,6 +615,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int PRIVATE_FLAG_PRODUCT = 1 << 19; /** + * Value for {@link #privateFlags}: whether this app is pre-installed on the + * google partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_PRODUCT_SERVICES = 1 << 21; + + /** * Value for {@link #privateFlags}: whether this app is signed with the * platform key. * @hide @@ -639,6 +646,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, PRIVATE_FLAG_PRIVILEGED, PRIVATE_FLAG_PRODUCT, + PRIVATE_FLAG_PRODUCT_SERVICES, PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY, PRIVATE_FLAG_STATIC_SHARED_LIBRARY, @@ -1888,6 +1896,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; } + /** @hide */ + public boolean isProductServices() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; + } + /** * Returns whether or not this application was installed as a virtual preload. */ diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 823d9951862c..20e1454e6276 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -649,14 +649,13 @@ public abstract class PackageManagerInternal { public abstract boolean isDataRestoreSafe(@NonNull Signature restoringFromSig, @NonNull String packageName); - /** - * Returns true if the the signing information for {@code clientUid} is sufficient to gain - * access gated by {@code capability}. This can happen if the two UIDs have the same signing - * information, if the signing information {@code clientUid} indicates that it has the signing - * certificate for {@code serverUid} in its signing history (if it was previously signed by it), - * or if the signing certificate for {@code clientUid} is in ths signing history for {@code - * serverUid} and with the {@code capability} specified. + * Returns {@code true} if the the signing information for {@code clientUid} is sufficient + * to gain access gated by {@code capability}. This can happen if the two UIDs have the + * same signing information, if the signing information {@code clientUid} indicates that + * it has the signing certificate for {@code serverUid} in its signing history (if it was + * previously signed by it), or if the signing certificate for {@code clientUid} is in the + * signing history for {@code serverUid} and with the {@code capability} specified. */ public abstract boolean hasSignatureCapability(int serverUid, int clientUid, @PackageParser.SigningDetails.CertCapabilities int capability); @@ -697,4 +696,10 @@ public abstract class PackageManagerInternal { */ public abstract void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException; + + /** Returns {@code true} if the specified component is enabled and matches the given flags. */ + public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId); + + /** Returns {@code true} if the given user requires extra badging for icons. */ + public abstract boolean userNeedsBadging(int userId); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 876cf2bda6fd..83757c4b523d 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6785,6 +6785,11 @@ public class PackageParser { } /** @hide */ + public boolean isProductServices() { + return applicationInfo.isProductServices(); + } + + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); } diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 19e399a50724..dfa30a22597e 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -1,17 +1,17 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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 + * 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 + * 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. + * 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.content.res; @@ -35,6 +35,7 @@ import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.ColorStateListDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.DrawableContainer; import android.icu.text.PluralRules; @@ -846,10 +847,15 @@ public class ResourcesImpl { stack.push(id); try { if (file.endsWith(".xml")) { - final XmlResourceParser rp = loadXmlResourceParser( - file, id, value.assetCookie, "drawable"); - dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null); - rp.close(); + if (file.startsWith("res/color/")) { + ColorStateList csl = loadColorStateList(wrapper, value, id, null); + dr = (csl != null ? new ColorStateListDrawable(csl) : null); + } else { + final XmlResourceParser rp = loadXmlResourceParser( + file, id, value.assetCookie, "drawable"); + dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null); + rp.close(); + } } else { final InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); @@ -1343,9 +1349,11 @@ public class ResourcesImpl { @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "obtainStyledAttributes"); + TypedArray array; synchronized (mKey) { final int len = attrs.length; - final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); + array = TypedArray.obtain(wrapper.getResources(), len); // XXX note that for now we only work with compiled XML files. // To support generic XML files we will need to manually parse @@ -1356,8 +1364,9 @@ public class ResourcesImpl { array.mDataAddress, array.mIndicesAddress); array.mTheme = wrapper; array.mXml = parser; - return array; } + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + return array; } @NonNull diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java index 5bf3a7c43640..06c069c583b5 100644 --- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java +++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java @@ -41,6 +41,7 @@ public class SQLiteCompatibilityWalFlags { private static volatile boolean sFlagsSet; private static volatile boolean sCompatibilityWalSupported; private static volatile String sWALSyncMode; + private static volatile long sTruncateSize = -1; // This flag is used to avoid recursive initialization due to circular dependency on Settings private static volatile boolean sCallingGlobalSettings; @@ -71,6 +72,19 @@ public class SQLiteCompatibilityWalFlags { return sWALSyncMode; } + /** + * Override {@link com.android.internal.R.integer#db_wal_truncate_size}. + * + * @return the value set in the global setting, or -1 if a value is not set. + * + * @hide + */ + @VisibleForTesting + public static long getTruncateSize() { + initIfNeeded(); + return sTruncateSize; + } + private static void initIfNeeded() { if (sInitialized || sCallingGlobalSettings) { return; @@ -115,6 +129,7 @@ public class SQLiteCompatibilityWalFlags { sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported", SQLiteGlobal.isCompatibilityWalSupported()); sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode()); + sTruncateSize = parser.getInt("truncate_size", -1); Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported=" + sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode); sFlagsSet = true; diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 3ca852a34594..5c4f16a7cf3d 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -33,6 +33,7 @@ import android.util.Printer; import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; +import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -308,6 +309,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } else { setSyncMode(SQLiteGlobal.getWALSyncMode()); } + maybeTruncateWalFile(); } else { setJournalMode(mConfiguration.journalMode == null ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); @@ -317,6 +319,40 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } } + /** + * If the WAL file exists and larger than a threshold, truncate it by executing + * PRAGMA wal_checkpoint. + */ + private void maybeTruncateWalFile() { + final long threshold = SQLiteGlobal.getWALTruncateSize(); + if (DEBUG) { + Log.d(TAG, "Truncate threshold=" + threshold); + } + if (threshold == 0) { + return; + } + + final File walFile = new File(mConfiguration.path + "-wal"); + if (!walFile.isFile()) { + return; + } + final long size = walFile.length(); + if (size < threshold) { + if (DEBUG) { + Log.d(TAG, walFile.getAbsolutePath() + " " + size + " bytes: No need to truncate"); + } + return; + } + + Log.i(TAG, walFile.getAbsolutePath() + " " + size + " bytes: Bigger than " + + threshold + "; truncating"); + try { + executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null); + } catch (SQLiteException e) { + Log.w(TAG, "Failed to truncate the -wal file", e); + } + } + private void setSyncMode(String newValue) { String value = executeForString("PRAGMA synchronous", null, null); if (!canonicalizeSyncMode(value).equalsIgnoreCase( diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index e6b6acf7b8ee..67e5f65d5a1f 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -164,4 +164,21 @@ public final class SQLiteGlobal { com.android.internal.R.integer.db_default_idle_connection_timeout)); } + /** + * When opening a database, if the WAL file is larger than this size, we'll truncate it. + * + * (If it's 0, we do not truncate.) + * + * @hide + */ + public static long getWALTruncateSize() { + final long setting = SQLiteCompatibilityWalFlags.getTruncateSize(); + if (setting >= 0) { + return setting; + } + return SystemProperties.getInt("debug.sqlite.wal.truncatesize", + Resources.getSystem().getInteger( + com.android.internal.R.integer.db_wal_truncate_size)); + } + } diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index de13c8132a65..12d0531bbf2b 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -549,7 +549,7 @@ public final class ContextHubManager { * Set a callback to receive messages from the context hub * * @param callback Callback object - * @param handler Handler object + * @param handler Handler object, if null uses the Handler of the main Looper * * @see Callback * @@ -568,7 +568,7 @@ public final class ContextHubManager { return -1; } mCallback = callback; - mCallbackHandler = handler; + mCallbackHandler = (handler == null) ? new Handler(mMainLooper) : handler; } return 0; } @@ -722,26 +722,31 @@ public final class ContextHubManager { return 0; } + /** + * Invokes the ContextHubManager.Callback callback registered with the ContextHubManager. + * + * @param hubId The ID of the Context Hub the message came from + * @param nanoAppId The instance ID of the nanoapp the message came from + * @param message The message to provide the callback + */ + private synchronized void invokeOnMessageReceiptCallback( + int hubId, int nanoAppId, ContextHubMessage message) { + if (mCallback != null) { + mCallback.onMessageReceipt(hubId, nanoAppId, message); + } + } + private final IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() { @Override - public void onMessageReceipt(final int hubId, final int nanoAppId, - final ContextHubMessage message) { - if (mCallback != null) { - synchronized(this) { - final Callback callback = mCallback; - Handler handler = mCallbackHandler == null ? - new Handler(mMainLooper) : mCallbackHandler; - handler.post(new Runnable() { - @Override - public void run() { - callback.onMessageReceipt(hubId, nanoAppId, message); - } - }); - } - } else if (mLocalCallback != null) { - // we always ensure that mCallback takes precedence, because mLocalCallback is only - // for internal compatibility - synchronized (this) { + public void onMessageReceipt( + final int hubId, final int nanoAppId, final ContextHubMessage message) { + synchronized (ContextHubManager.this) { + if (mCallback != null) { + mCallbackHandler.post( + () -> invokeOnMessageReceiptCallback(hubId, nanoAppId, message)); + } else if (mLocalCallback != null) { + // We always ensure that mCallback takes precedence, because mLocalCallback is + // only for internal compatibility mLocalCallback.onMessageReceipt(hubId, nanoAppId, message); } } diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 7543920e363f..3319f33878c1 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -35,7 +35,7 @@ public class IpConfiguration implements Parcelable { * with staticIpConfiguration */ @UnsupportedAppUsage STATIC, - /* Use dynamically configured IP settigns */ + /* Use dynamically configured IP settings */ DHCP, /* no IP details are assigned, this is used to indicate * that any existing IP settings should be retained */ diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 599ccb287a26..34e9476b3e08 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -22,6 +22,7 @@ import android.util.Log; import android.util.Pair; import java.io.FileDescriptor; +import java.io.IOException; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; @@ -131,6 +132,17 @@ public class NetworkUtils { public native static boolean queryUserAccess(int uid, int netId); /** + * Add an entry into the ARP cache. + */ + public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname, + FileDescriptor fd) throws IOException { + addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd); + } + + private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname, + FileDescriptor fd) throws IOException; + + /** * @see #intToInet4AddressHTL(int) * @deprecated Use either {@link #intToInet4AddressHTH(int)} * or {@link #intToInet4AddressHTL(int)} @@ -149,7 +161,7 @@ public class NetworkUtils { * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is * lower-order IPv4 address byte */ - public static InetAddress intToInet4AddressHTL(int hostAddress) { + public static Inet4Address intToInet4AddressHTL(int hostAddress) { return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); } @@ -157,14 +169,14 @@ public class NetworkUtils { * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) * @param hostAddress an int coding for an IPv4 address */ - public static InetAddress intToInet4AddressHTH(int hostAddress) { + public static Inet4Address intToInet4AddressHTH(int hostAddress) { byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), (byte) (0xff & (hostAddress >> 16)), (byte) (0xff & (hostAddress >> 8)), (byte) (0xff & hostAddress) }; try { - return InetAddress.getByAddress(addressBytes); + return (Inet4Address) InetAddress.getByAddress(addressBytes); } catch (UnknownHostException e) { throw new AssertionError(); } @@ -397,6 +409,28 @@ public class NetworkUtils { } /** + * Get a prefix mask as Inet4Address for a given prefix length. + * + * <p>For example 20 -> 255.255.240.0 + */ + public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) + throws IllegalArgumentException { + return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } + + /** + * Get the broadcast address for a given prefix. + * + * <p>For example 192.168.0.1/24 -> 192.168.0.255 + */ + public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) + throws IllegalArgumentException { + final int intBroadcastAddr = inet4AddressToIntHTH(addr) + | ~prefixLengthToV4NetmaskIntHTH(prefixLength); + return intToInet4AddressHTH(intBroadcastAddr); + } + + /** * Check if IP address type is consistent between two InetAddress. * @return true if both are the same type. False otherwise. */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index e32ed9deb270..347f60f6b9be 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -45,6 +45,7 @@ public class Environment { private static final String ENV_ODM_ROOT = "ODM_ROOT"; private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; + private static final String ENV_PRODUCT_SERVICES_ROOT = "PRODUCT_SERVICES_ROOT"; /** {@hide} */ public static final String DIR_ANDROID = "Android"; @@ -67,6 +68,8 @@ public class Environment { private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product"); + private static final File DIR_PRODUCT_SERVICES_ROOT = getDirectory(ENV_PRODUCT_SERVICES_ROOT, + "/product_services"); private static UserEnvironment sCurrentUser; private static boolean sUserRequired; @@ -196,6 +199,16 @@ public class Environment { } /** + * Return root directory of the "product_services" partition holding middleware + * services if any. If present, the partition is mounted read-only. + * + * @hide + */ + public static File getProductServicesDirectory() { + return DIR_PRODUCT_SERVICES_ROOT; + } + + /** * Return the system directory for a user. This is for use by system * services to store files relating to the user. This directory will be * automatically deleted when the user is removed. diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 067e8493717b..732d3778ec6d 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -384,7 +384,10 @@ public class ZygoteProcess { argsForZygote.add("--mount-external-read"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) { argsForZygote.add("--mount-external-write"); + } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) { + argsForZygote.add("--mount-external-full"); } + argsForZygote.add("--target-sdk-version=" + targetSdkVersion); // --setgroups is a comma-separated list diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index d102b194f86d..d850e27e913f 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -79,4 +79,18 @@ public abstract class StorageManagerInternal { * @return The mount mode. */ public abstract int getExternalStorageMountMode(int uid, String packageName); + + /** + * Mount external storage for the given package. + * + * <p> This will involve calling into vold to setup appropriate bind mounts. + * + * @param packageName The package for which external storage will be mounted. + * @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 + */ + public abstract void mountExternalStorageForApp(String packageName, int appId, + String sharedUserId, int userId); } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index ad7b103d5e99..e8daf2120151 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -104,7 +104,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba @UnsupportedAppUsage public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) { - this(context, streamType, defaultUri, callback, true); + this(context, streamType, defaultUri, callback, true /* playSample */); } public SeekBarVolumizer( diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java index 67c6fb98aa6b..6427af6cb175 100644 --- a/core/java/android/provider/BlockedNumberContract.java +++ b/core/java/android/provider/BlockedNumberContract.java @@ -15,12 +15,16 @@ */ package android.provider; +import android.annotation.IntDef; import android.annotation.WorkerThread; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.telecom.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * <p> * The contract between the blockednumber provider and applications. Contains definitions for @@ -220,6 +224,63 @@ public class BlockedNumberContract { public static final String RES_NUMBER_IS_BLOCKED = "blocked"; /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "STATUS_" }, + value = {STATUS_NOT_BLOCKED, STATUS_BLOCKED_IN_LIST, STATUS_BLOCKED_RESTRICTED, + STATUS_BLOCKED_UNKNOWN_NUMBER, STATUS_BLOCKED_PAYPHONE, + STATUS_BLOCKED_NOT_IN_CONTACTS}) + public @interface BlockStatus {} + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was not + * blocked. + * @hide + */ + public static final int STATUS_NOT_BLOCKED = 0; + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked + * because it is in the list of blocked numbers maintained by the provider. + * @hide + */ + public static final int STATUS_BLOCKED_IN_LIST = 1; + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked + * because it is from a restricted number. + * @hide + */ + public static final int STATUS_BLOCKED_RESTRICTED = 2; + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked + * because it is from an unknown number. + * @hide + */ + public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked + * because it is from a pay phone. + * @hide + */ + public static final int STATUS_BLOCKED_PAYPHONE = 4; + + /** + * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked + * because it is from a number not in the users contacts. + * @hide + */ + public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; + + /** + * Integer reason indicating whether a call was blocked, and if so why. + * @hide + */ + public static final String RES_BLOCK_STATUS = "block_status"; + + /** @hide */ public static final String RES_NUM_ROWS_DELETED = "num_deleted"; /** @hide */ @@ -411,19 +472,23 @@ public class BlockedNumberContract { * @param context the context of the caller. * @param phoneNumber the number to check. * @param extras the extra attribute of the number. - * @return {@code true} if should block the number. {@code false} otherwise. + * @return result code indicating if the number should be blocked, and if so why. + * Valid values are: {@link #STATUS_NOT_BLOCKED}, {@link #STATUS_BLOCKED_IN_LIST}, + * {@link #STATUS_BLOCKED_NOT_IN_CONTACTS}, {@link #STATUS_BLOCKED_PAYPHONE}, + * {@link #STATUS_BLOCKED_RESTRICTED}, {@link #STATUS_BLOCKED_UNKNOWN_NUMBER}. */ - public static boolean shouldSystemBlockNumber(Context context, String phoneNumber, + public static int shouldSystemBlockNumber(Context context, String phoneNumber, Bundle extras) { try { final Bundle res = context.getContentResolver().call( AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras); - return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false); + return res != null ? res.getInt(RES_BLOCK_STATUS, STATUS_NOT_BLOCKED) : + BlockedNumberContract.STATUS_NOT_BLOCKED; } catch (NullPointerException | IllegalArgumentException ex) { // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if // either of these happen. Log.w(null, "shouldSystemBlockNumber: provider not ready."); - return false; + return BlockedNumberContract.STATUS_NOT_BLOCKED; } } @@ -504,6 +569,28 @@ public class BlockedNumberContract { } /** + * Converts a block status constant to a string equivalent for logging. + * @hide + */ + public static String blockStatusToString(int blockStatus) { + switch (blockStatus) { + case STATUS_NOT_BLOCKED: + return "not blocked"; + case STATUS_BLOCKED_IN_LIST: + return "blocked - in list"; + case STATUS_BLOCKED_RESTRICTED: + return "blocked - restricted"; + case STATUS_BLOCKED_UNKNOWN_NUMBER: + return "blocked - unknown"; + case STATUS_BLOCKED_PAYPHONE: + return "blocked - payphone"; + case STATUS_BLOCKED_NOT_IN_CONTACTS: + return "blocked - not in contacts"; + } + return "unknown"; + } + + /** * Represents the current status of * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7980af12b821..bffed8dcfdf2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13114,6 +13114,7 @@ public final class Settings { * Supported keys: * compatibility_wal_supported (boolean) * wal_syncmode (String) + * truncate_size (int) * * @hide */ diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java index 76d5328d2fc5..e5f3dfbe2a1c 100644 --- a/core/java/android/service/notification/NotificationStats.java +++ b/core/java/android/service/notification/NotificationStats.java @@ -71,6 +71,37 @@ public final class NotificationStats implements Parcelable { */ public static final int DISMISSAL_SHADE = 3; + /** @hide */ + @IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = { + DISMISS_SENTIMENT_UNKNOWN, DISMISS_SENTIMENT_NEGATIVE, DISMISS_SENTIMENT_NEUTRAL, + DISMISS_SENTIMENT_POSITIVE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DismissalSentiment {} + + /** + * No information is available about why this notification was dismissed, or the notification + * isn't dismissed yet. + */ + public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; + /** + * The user indicated while dismissing that they did not like the notification. + */ + public static final int DISMISS_SENTIMENT_NEGATIVE = 0; + /** + * The user didn't indicate one way or another how they felt about the notification while + * dismissing it. + */ + public static final int DISMISS_SENTIMENT_NEUTRAL = 1; + /** + * The user indicated while dismissing that they did like the notification. + */ + public static final int DISMISS_SENTIMENT_POSITIVE = 2; + + + private @DismissalSentiment + int mDismissalSentiment = DISMISS_SENTIMENT_UNKNOWN; + public NotificationStats() { } @@ -82,6 +113,7 @@ public final class NotificationStats implements Parcelable { mViewedSettings = in.readByte() != 0; mInteracted = in.readByte() != 0; mDismissalSurface = in.readInt(); + mDismissalSentiment = in.readInt(); } @Override @@ -93,6 +125,7 @@ public final class NotificationStats implements Parcelable { dest.writeByte((byte) (mViewedSettings ? 1 : 0)); dest.writeByte((byte) (mInteracted ? 1 : 0)); dest.writeInt(mDismissalSurface); + dest.writeInt(mDismissalSentiment); } @Override @@ -212,6 +245,21 @@ public final class NotificationStats implements Parcelable { mDismissalSurface = dismissalSurface; } + /** + * Records whether the user indicated how they felt about a notification before or + * during dismissal. + */ + public void setDismissalSentiment(@DismissalSentiment int dismissalSentiment) { + mDismissalSentiment = dismissalSentiment; + } + + /** + * Returns how the user indicated they felt about a notification before or during dismissal. + */ + public @DismissalSentiment int getDismissalSentiment() { + return mDismissalSentiment; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 0f8ca44e5f93..a7f14b6bf0c6 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -40,11 +40,11 @@ public class FeatureFlagUtils { static { DEFAULT_FLAGS = new HashMap<>(); DEFAULT_FLAGS.put("settings_battery_display_app_list", "false"); - DEFAULT_FLAGS.put("settings_condition_manager_v2", "true"); DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false"); DEFAULT_FLAGS.put("settings_audio_switcher", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put("settings_dynamic_homepage", "false"); + DEFAULT_FLAGS.put("settings_mobile_network_v2", "false"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true"); } diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index a7755a288530..4b946d7f430f 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -40,7 +40,7 @@ public final class DisplayListCanvas extends RecordingCanvas { // view hierarchy because display lists are generated recursively. private static final int POOL_LIMIT = 25; - private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB + public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB private static final SynchronizedPool<DisplayListCanvas> sPool = new SynchronizedPool<>(POOL_LIMIT); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 6268a4a8d9d0..0119d2e6b8b0 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -8663,7 +8663,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Compare two views based on their bounds. Use the bounds of their children to break ties. * * @param holder1 Holder of first view to compare - * @param holder2 Holder of second view to compare. Must have the same root at holder1. + * @param holder2 Holder of second view to compare. Must have the same root as holder1. * @return The compare result, with equality if no good comparison was found. */ private static int compareBoundsOfTree( @@ -8756,6 +8756,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private void clear() { mView = null; + mRoot = null; mLocation.set(0, 0, 0, 0); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 23fc4d5045a9..1351f6f1ef26 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.View.PFLAG_DRAW_ANIMATION; import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER; @@ -1212,13 +1213,30 @@ public final class ViewRootImpl implements ViewParent, // Get new instance of display based on current display adjustments. It may be updated later // if moving between the displays also involved a configuration change. - mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId, - mView.getResources()); + updateInternalDisplay(displayId, mView.getResources()); mAttachInfo.mDisplayState = mDisplay.getState(); // Internal state updated, now notify the view hierarchy. mView.dispatchMovedToDisplay(mDisplay, config); } + /** + * Updates {@link #mDisplay} to the display object corresponding to {@param displayId}. + * Uses DEFAULT_DISPLAY if there isn't a display object in the system corresponding + * to {@param displayId}. + */ + private void updateInternalDisplay(int displayId, Resources resources) { + final Display preferredDisplay = + ResourcesManager.getInstance().getAdjustedDisplay(displayId, resources); + if (preferredDisplay == null) { + // Fallback to use default display. + Slog.w(TAG, "Cannot get desired display with Id: " + displayId); + mDisplay = ResourcesManager.getInstance() + .getAdjustedDisplay(DEFAULT_DISPLAY, resources); + } else { + mDisplay = preferredDisplay; + } + } + void pokeDrawLockIfNeeded() { final int displayState = mAttachInfo.mDisplayState; if (mView != null && mAdded && mTraversalScheduled @@ -3944,8 +3962,7 @@ public final class ViewRootImpl implements ViewParent, // Handle configuration change. if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) { // Update the display with new DisplayAdjustments. - mDisplay = ResourcesManager.getInstance().getAdjustedDisplay( - mDisplay.getDisplayId(), localResources); + updateInternalDisplay(mDisplay.getDisplayId(), localResources); final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection(); final int currentLayoutDirection = config.getLayoutDirection(); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 2cd4b2bca898..9419e93d0066 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1413,7 +1413,7 @@ public final class AutofillManager { try { mService.getAvailableFieldClassificationAlgorithms(receiver); final String[] algorithms = receiver - .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY); + .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY); return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList(); } catch (RemoteException e) { e.rethrowFromSystemServer(); diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java index dba74b191b09..f88a4e2b414f 100644 --- a/core/java/android/widget/DatePickerSpinnerDelegate.java +++ b/core/java/android/widget/DatePickerSpinnerDelegate.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; @@ -502,6 +503,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth); } + @UnsupportedAppUsage private void setDate(int year, int month, int dayOfMonth) { mCurrentDate.set(year, month, dayOfMonth); resetAutofilledValue(); @@ -512,6 +514,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { } } + @UnsupportedAppUsage private void updateSpinners() { // set the spinner ranges respecting the min and max dates if (mCurrentDate.equals(mMinDate)) { @@ -564,6 +567,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { /** * Updates the calendar view with the current date. */ + @UnsupportedAppUsage private void updateCalendarView() { mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false); } @@ -572,6 +576,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { /** * Notifies the listener, if such, for a change in the selected date. */ + @UnsupportedAppUsage private void notifyDateChanged() { mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); if (mOnDateChangedListener != null) { @@ -627,6 +632,7 @@ class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate { } } + @UnsupportedAppUsage private void updateInputState() { // Make sure that if the user changes the value and the IME is active // for one of the inputs if this widget, the IME is closed. If the user diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 11054c81f342..5734171379a9 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -76,10 +76,10 @@ public final class Magnifier { private final int mWindowHeight; // The zoom applied to the view region copied to the magnifier window. private final float mZoom; - // The width of the bitmaps where the magnifier content is copied. - private final int mBitmapWidth; - // The height of the bitmaps where the magnifier content is copied. - private final int mBitmapHeight; + // The width of the content that will be copied to the magnifier. + private final int mSourceWidth; + // The height of the content that will be copied to the magnifier. + private final int mSourceHeight; // The elevation of the window containing the magnifier. private final float mWindowElevation; // The corner radius of the window containing the magnifier. @@ -91,15 +91,14 @@ public final class Magnifier { // The center coordinates of the window containing the magnifier. private final Point mWindowCoords = new Point(); // The center coordinates of the content to be magnified, - // which can potentially contain a region outside the magnified view. - private final Point mCenterZoomCoords = new Point(); - // The center coordinates of the content to be magnified, // clamped inside the visible region of the magnified view. private final Point mClampedCenterZoomCoords = new Point(); // Variables holding previous states, used for detecting redundant calls and invalidation. private final Point mPrevStartCoordsInSurface = new Point( NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE); - private final PointF mPrevPosInView = new PointF( + private final PointF mPrevShowSourceCoords = new PointF( + NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE); + private final PointF mPrevShowWindowCoords = new PointF( NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE); // Rectangle defining the view surface area we pixel copy content from. private final Rect mPixelCopyRequestRect = new Rect(); @@ -120,8 +119,8 @@ public final class Magnifier { mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation); mWindowCornerRadius = getDeviceDefaultDialogCornerRadius(); mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale); - mBitmapWidth = Math.round(mWindowWidth / mZoom); - mBitmapHeight = Math.round(mWindowHeight / mZoom); + mSourceWidth = Math.round(mWindowWidth / mZoom); + mSourceHeight = Math.round(mWindowHeight / mZoom); // The view's surface coordinates will not be updated until the magnifier is first shown. mViewCoordinatesInSurface = new int[2]; } @@ -148,25 +147,50 @@ public final class Magnifier { /** * Shows the magnifier on the screen. * - * @param xPosInView horizontal coordinate of the center point of the magnifier source relative - * to the view. The lower end is clamped to 0 and the higher end is clamped to the view - * width. - * @param yPosInView vertical coordinate of the center point of the magnifier source - * relative to the view. The lower end is clamped to 0 and the higher end is clamped to - * the view height. + * @param sourceCenterX horizontal coordinate of the center point of the source rectangle that + * will be magnified and copied to the magnifier, relative to the view. + * The parameter is clamped such that the copy rectangle fits inside [0, view width]. + * @param sourceCenterY vertical coordinate of the center point of the source rectangle that + * will be magnified and copied to the magnifier, relative to the view. + * The parameter is clamped such that the copy rectangle fits inside [0, view height]. + */ + public void show(@FloatRange(from = 0) float sourceCenterX, + @FloatRange(from = 0) float sourceCenterY) { + final int verticalOffset = mView.getContext().getResources() + .getDimensionPixelSize(R.dimen.magnifier_offset); + show(sourceCenterX, sourceCenterY, sourceCenterX, sourceCenterY - verticalOffset); + } + + /** + * Shows the magnifier on the screen at a position + * that is independent from its content position. + * + * @param sourceCenterX horizontal coordinate of the center point of the source rectangle that + * will be magnified and copied to the magnifier, relative to the view. + * The parameter is clamped such that the copy rectangle fits inside [0, view width]. + * @param sourceCenterY vertical coordinate of the center point of the source rectangle that + * will be magnified and copied to the magnifier, relative to the view. + * The parameter is clamped such that the copy rectangle fits inside [0, view height]. + * @param magnifierCenterX horizontal coordinate of the center point of the magnifier window + * relative to the view. As the magnifier can be arbitrarily positioned, this can be + * negative or larger than the view width. + * @param magnifierCenterY vertical coordinate of the center point of the magnifier window + * relative to the view. As the magnifier can be arbitrarily positioned, this can be + * negative or larger than the view height. */ - public void show(@FloatRange(from = 0) float xPosInView, - @FloatRange(from = 0) float yPosInView) { - xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth())); - yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight())); + public void show(@FloatRange(from = 0) float sourceCenterX, + @FloatRange(from = 0) float sourceCenterY, + float magnifierCenterX, float magnifierCenterY) { + sourceCenterX = Math.max(0, Math.min(sourceCenterX, mView.getWidth())); + sourceCenterY = Math.max(0, Math.min(sourceCenterY, mView.getHeight())); obtainSurfaces(); - obtainContentCoordinates(xPosInView, yPosInView); - obtainWindowCoordinates(); + obtainContentCoordinates(sourceCenterX, sourceCenterY); + obtainWindowCoordinates(magnifierCenterX, magnifierCenterY); - final int startX = mClampedCenterZoomCoords.x - mBitmapWidth / 2; - final int startY = mClampedCenterZoomCoords.y - mBitmapHeight / 2; - if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) { + final int startX = mClampedCenterZoomCoords.x - mSourceWidth / 2; + final int startY = mClampedCenterZoomCoords.y - mSourceHeight / 2; + if (sourceCenterX != mPrevShowSourceCoords.x || sourceCenterY != mPrevShowSourceCoords.y) { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), @@ -177,9 +201,24 @@ public final class Magnifier { } } performPixelCopy(startX, startY, true /* update window position */); - mPrevPosInView.x = xPosInView; - mPrevPosInView.y = yPosInView; + } else if (magnifierCenterX != mPrevShowWindowCoords.x + || magnifierCenterY != mPrevShowWindowCoords.y) { + final Point windowCoords = getCurrentClampedWindowCoordinates(); + final InternalPopupWindow currentWindowInstance = mWindow; + sPixelCopyHandlerThread.getThreadHandler().post(() -> { + if (mWindow != currentWindowInstance) { + // The magnifier was dismissed (and maybe shown again) in the meantime. + return; + } + synchronized (mLock) { + mWindow.setContentPositionForNextDraw(windowCoords.x, windowCoords.y); + } + }); } + mPrevShowSourceCoords.x = sourceCenterX; + mPrevShowSourceCoords.y = sourceCenterY; + mPrevShowWindowCoords.x = magnifierCenterX; + mPrevShowWindowCoords.y = magnifierCenterY; } /** @@ -191,8 +230,10 @@ public final class Magnifier { mWindow.destroy(); mWindow = null; } - mPrevPosInView.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE; - mPrevPosInView.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE; + mPrevShowSourceCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE; + mPrevShowSourceCoords.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE; + mPrevShowWindowCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE; + mPrevShowWindowCoords.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE; mPrevStartCoordsInSurface.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE; mPrevStartCoordsInSurface.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE; } @@ -296,19 +337,17 @@ public final class Magnifier { * magnifier. These are relative to the surface the content is copied from. */ private void obtainContentCoordinates(final float xPosInView, final float yPosInView) { - final float posX; - final float posY; mView.getLocationInSurface(mViewCoordinatesInSurface); + final int zoomCenterX; + final int zoomCenterY; if (mView instanceof SurfaceView) { // No offset required if the backing Surface matches the size of the SurfaceView. - posX = xPosInView; - posY = yPosInView; + zoomCenterX = Math.round(xPosInView); + zoomCenterY = Math.round(yPosInView); } else { - posX = xPosInView + mViewCoordinatesInSurface[0]; - posY = yPosInView + mViewCoordinatesInSurface[1]; + zoomCenterX = Math.round(xPosInView + mViewCoordinatesInSurface[0]); + zoomCenterY = Math.round(yPosInView + mViewCoordinatesInSurface[1]); } - mCenterZoomCoords.x = Math.round(posX); - mCenterZoomCoords.y = Math.round(posY); // Clamp the x location to avoid magnifying content which does not belong // to the magnified view. This will not take into account overlapping views. @@ -323,18 +362,29 @@ public final class Magnifier { // If we copy content from a SurfaceView, clamp coordinates relative to it. viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]); } - mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mBitmapWidth / 2, Math.min( - mCenterZoomCoords.x, viewVisibleRegion.right - mBitmapWidth / 2)); - mClampedCenterZoomCoords.y = mCenterZoomCoords.y; + mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mSourceWidth / 2, Math.min( + zoomCenterX, viewVisibleRegion.right - mSourceWidth / 2)); + mClampedCenterZoomCoords.y = zoomCenterY; } - private void obtainWindowCoordinates() { - // Compute the position of the magnifier window. Again, this has to be relative to the - // surface of the magnified view, as this surface is the parent of the magnifier surface. - final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize( - R.dimen.magnifier_offset); - mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2; - mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset; + /** + * Computes the coordinates of the top left corner of the magnifier window. + * These are relative to the surface the magnifier window is attached to. + */ + private void obtainWindowCoordinates(final float xWindowPos, final float yWindowPos) { + final int windowCenterX; + final int windowCenterY; + if (mView instanceof SurfaceView) { + // No offset required if the backing Surface matches the size of the SurfaceView. + windowCenterX = Math.round(xWindowPos); + windowCenterY = Math.round(yWindowPos); + } else { + windowCenterX = Math.round(xWindowPos + mViewCoordinatesInSurface[0]); + windowCenterY = Math.round(yWindowPos + mViewCoordinatesInSurface[1]); + } + + mWindowCoords.x = windowCenterX - mWindowWidth / 2; + mWindowCoords.y = windowCenterY - mWindowHeight / 2; if (mParentSurface != mContentCopySurface) { mWindowCoords.x += mViewCoordinatesInSurface[0]; mWindowCoords.y += mViewCoordinatesInSurface[1]; @@ -348,34 +398,21 @@ public final class Magnifier { } // Clamp copy coordinates inside the surface to avoid displaying distorted content. final int clampedStartXInSurface = Math.max(0, - Math.min(startXInSurface, mContentCopySurface.mWidth - mBitmapWidth)); + Math.min(startXInSurface, mContentCopySurface.mWidth - mSourceWidth)); final int clampedStartYInSurface = Math.max(0, - Math.min(startYInSurface, mContentCopySurface.mHeight - mBitmapHeight)); - + Math.min(startYInSurface, mContentCopySurface.mHeight - mSourceHeight)); // Clamp window coordinates inside the parent surface, to avoid displaying // the magnifier out of screen or overlapping with system insets. - final Rect windowBounds; - if (mParentSurface.mIsMainWindowSurface) { - final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); - windowBounds = new Rect(systemInsets.left, systemInsets.top, - mParentSurface.mWidth - systemInsets.right, - mParentSurface.mHeight - systemInsets.bottom); - } else { - windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); - } - final int windowCoordsX = Math.max(windowBounds.left, - Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x)); - final int windowCoordsY = Math.max(windowBounds.top, - Math.min(windowBounds.bottom - mWindowHeight, mWindowCoords.y)); + final Point windowCoords = getCurrentClampedWindowCoordinates(); // Perform the pixel copy. mPixelCopyRequestRect.set(clampedStartXInSurface, clampedStartYInSurface, - clampedStartXInSurface + mBitmapWidth, - clampedStartYInSurface + mBitmapHeight); + clampedStartXInSurface + mSourceWidth, + clampedStartYInSurface + mSourceHeight); final InternalPopupWindow currentWindowInstance = mWindow; final Bitmap bitmap = - Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888); + Bitmap.createBitmap(mSourceWidth, mSourceHeight, Bitmap.Config.ARGB_8888); PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap, result -> { synchronized (mLock) { @@ -385,7 +422,7 @@ public final class Magnifier { } if (updateWindowPosition) { // TODO: pull the position update outside #performPixelCopy - mWindow.setContentPositionForNextDraw(windowCoordsX, windowCoordsY); + mWindow.setContentPositionForNextDraw(windowCoords.x, windowCoords.y); } mWindow.updateContent(bitmap); } @@ -396,6 +433,28 @@ public final class Magnifier { } /** + * Clamp window coordinates inside the surface the magnifier is attached to, to avoid + * displaying the magnifier out of screen or overlapping with system insets. + * @return the current window coordinates, after they are clamped inside the parent surface + */ + private Point getCurrentClampedWindowCoordinates() { + final Rect windowBounds; + if (mParentSurface.mIsMainWindowSurface) { + final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); + windowBounds = new Rect(systemInsets.left, systemInsets.top, + mParentSurface.mWidth - systemInsets.right, + mParentSurface.mHeight - systemInsets.bottom); + } else { + windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); + } + final int windowCoordsX = Math.max(windowBounds.left, + Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x)); + final int windowCoordsY = Math.max(windowBounds.top, + Math.min(windowBounds.bottom - mWindowHeight, mWindowCoords.y)); + return new Point(windowCoordsX, windowCoordsY); + } + + /** * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS index e4b2930a23cb..5c79d21791e3 100644 --- a/core/java/android/widget/OWNERS +++ b/core/java/android/widget/OWNERS @@ -1,11 +1 @@ -per-file TextView.java = siyamed@google.com -per-file TextView.java = nona@google.com -per-file TextView.java = clarabayarri@google.com - -per-file EditText.java = siyamed@google.com -per-file EditText.java = nona@google.com -per-file EditText.java = clarabayarri@google.com - -per-file Editor.java = siyamed@google.com -per-file Editor.java = nona@google.com -per-file Editor.java = clarabayarri@google.com +per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 8fa8ef88a3ad..35ff6cc23499 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -16,8 +16,6 @@ package android.widget; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; - import android.annotation.ColorInt; import android.annotation.DimenRes; import android.annotation.NonNull; @@ -364,29 +362,12 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public static class OnClickHandler { - private int mEnterAnimationId; - @UnsupportedAppUsage - public boolean onClickHandler(View view, PendingIntent pendingIntent, - Intent fillInIntent) { - return onClickHandler(view, pendingIntent, fillInIntent, WINDOWING_MODE_UNDEFINED); - } - - public boolean onClickHandler(View view, PendingIntent pendingIntent, - Intent fillInIntent, int windowingMode) { + public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { try { // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? Context context = view.getContext(); - ActivityOptions opts; - if (mEnterAnimationId != 0) { - opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0); - } else { - opts = ActivityOptions.makeBasic(); - } - - if (windowingMode != WINDOWING_MODE_UNDEFINED) { - opts.setLaunchWindowingMode(windowingMode); - } + ActivityOptions opts = getActivityOptions(context); context.startIntentSender( pendingIntent.getIntentSender(), fillInIntent, Intent.FLAG_ACTIVITY_NEW_TASK, @@ -402,8 +383,26 @@ public class RemoteViews implements Parcelable, Filter { return true; } - public void setEnterAnimationId(int enterAnimationId) { - mEnterAnimationId = enterAnimationId; + /** @hide */ + protected ActivityOptions getActivityOptions(Context context) { + if (context.getResources().getBoolean( + com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) { + TypedArray windowStyle = context.getTheme().obtainStyledAttributes( + com.android.internal.R.styleable.Window); + int windowAnimations = windowStyle.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + TypedArray windowAnimationStyle = context.obtainStyledAttributes( + windowAnimations, com.android.internal.R.styleable.WindowAnimation); + int enterAnimationId = windowAnimationStyle.getResourceId(com.android.internal.R + .styleable.WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0); + windowStyle.recycle(); + windowAnimationStyle.recycle(); + + if (enterAnimationId != 0) { + return ActivityOptions.makeCustomAnimation(context, enterAnimationId, 0); + } + } + return ActivityOptions.makeBasic(); } } @@ -3324,8 +3323,6 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews rvToApply = getRemoteViewsToApply(context); View result = inflateView(context, rvToApply, parent); - loadTransitionOverride(context, handler); - rvToApply.performApply(result, parent, handler); return result; @@ -3355,24 +3352,6 @@ public class RemoteViews implements Parcelable, Filter { return v; } - private static void loadTransitionOverride(Context context, - RemoteViews.OnClickHandler handler) { - if (handler != null && context.getResources().getBoolean( - com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) { - TypedArray windowStyle = context.getTheme().obtainStyledAttributes( - com.android.internal.R.styleable.Window); - int windowAnimations = windowStyle.getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, 0); - TypedArray windowAnimationStyle = context.obtainStyledAttributes( - windowAnimations, com.android.internal.R.styleable.WindowAnimation); - handler.setEnterAnimationId(windowAnimationStyle.getResourceId( - com.android.internal.R.styleable. - WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0)); - windowStyle.recycle(); - windowAnimationStyle.recycle(); - } - } - /** * Implement this interface to receive a callback when * {@link #applyAsync} or {@link #reapplyAsync} is finished. @@ -3445,7 +3424,6 @@ public class RemoteViews implements Parcelable, Filter { mHandler = handler; mResult = result; - loadTransitionOverride(context, handler); } @Override diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index ae9c5c42d659..8cfe1c1fc7db 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -28,7 +28,6 @@ import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -59,9 +58,11 @@ public class IntentForwarderActivity extends Activity { public static String FORWARD_INTENT_TO_MANAGED_PROFILE = "com.android.internal.app.ForwardIntentToManagedProfile"; - private static final Set<String> ALLOWED_TEXT_MESSAGE_SCHEME + private static final Set<String> ALLOWED_TEXT_MESSAGE_SCHEMES = new HashSet<>(Arrays.asList("sms", "smsto", "mms", "mmsto")); + private static final String TEL_SCHEME = "tel"; + private Injector mInjector; @Override @@ -144,13 +145,21 @@ public class IntentForwarderActivity extends Activity { } private boolean isTextMessageIntent(Intent intent) { - return Intent.ACTION_SENDTO.equals(intent.getAction()) && intent.getData() != null - && ALLOWED_TEXT_MESSAGE_SCHEME.contains(intent.getData().getScheme()); + return (Intent.ACTION_SENDTO.equals(intent.getAction()) || isViewActionIntent(intent)) + && ALLOWED_TEXT_MESSAGE_SCHEMES.contains(intent.getScheme()); } private boolean isDialerIntent(Intent intent) { return Intent.ACTION_DIAL.equals(intent.getAction()) - || Intent.ACTION_CALL.equals(intent.getAction()); + || Intent.ACTION_CALL.equals(intent.getAction()) + || Intent.ACTION_CALL_PRIVILEGED.equals(intent.getAction()) + || Intent.ACTION_CALL_EMERGENCY.equals(intent.getAction()) + || (isViewActionIntent(intent) && TEL_SCHEME.equals(intent.getScheme())); + } + + private boolean isViewActionIntent(Intent intent) { + return Intent.ACTION_VIEW.equals(intent.getAction()) + && intent.hasCategory(Intent.CATEGORY_BROWSABLE); } private boolean isTargetResolverOrChooserActivity(ActivityInfo activityInfo) { diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java index 1b3faf5a6d59..119f30df8946 100644 --- a/core/java/com/android/internal/app/WindowDecorActionBar.java +++ b/core/java/com/android/internal/app/WindowDecorActionBar.java @@ -33,6 +33,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.annotation.UnsupportedAppUsage; import android.app.ActionBar; import android.app.Activity; import android.app.Dialog; @@ -79,6 +80,7 @@ public class WindowDecorActionBar extends ActionBar implements private ActionBarOverlayLayout mOverlayLayout; private ActionBarContainer mContainerView; private DecorToolbar mDecorToolbar; + @UnsupportedAppUsage private ActionBarContextView mContextView; private ActionBarContainer mSplitView; private View mContentView; diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index f89a9d990b76..0c6f832ff33a 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -374,8 +374,12 @@ public abstract class FileSystemProvider extends DocumentsProvider { final File parent = getFileForDocId(parentDocumentId); final MatrixCursor result = new DirectoryCursor( resolveProjection(projection), parentDocumentId, parent); - for (File file : parent.listFiles()) { - includeFile(result, null, file); + if (parent.isDirectory()) { + for (File file : FileUtils.listFilesOrEmpty(parent)) { + includeFile(result, null, file); + } + } else { + Log.w(TAG, "parentDocumentId '" + parentDocumentId + "' is not Directory"); } return result; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index c65dd6fc1bb2..07f74f0506b2 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6724,7 +6724,7 @@ public class BatteryStatsImpl extends BatteryStats { int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED; StopwatchTimer[] mWifiBatchedScanTimer; - boolean mWifiMulticastEnabled; + int mWifiMulticastWakelockCount; StopwatchTimer mWifiMulticastTimer; StopwatchTimer mAudioTurnedOnTimer; @@ -7183,8 +7183,7 @@ public class BatteryStatsImpl extends BatteryStats { @Override public void noteWifiMulticastEnabledLocked(long elapsedRealtimeMs) { - if (!mWifiMulticastEnabled) { - mWifiMulticastEnabled = true; + if (mWifiMulticastWakelockCount == 0) { if (mWifiMulticastTimer == null) { mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase); @@ -7194,12 +7193,17 @@ public class BatteryStatsImpl extends BatteryStats { StatsLog.WIFI_MULTICAST_LOCK_STATE_CHANGED, getUid(), null, StatsLog.WIFI_MULTICAST_LOCK_STATE_CHANGED__STATE__ON); } + mWifiMulticastWakelockCount++; } @Override public void noteWifiMulticastDisabledLocked(long elapsedRealtimeMs) { - if (mWifiMulticastEnabled) { - mWifiMulticastEnabled = false; + if (mWifiMulticastWakelockCount == 0) { + return; + } + + mWifiMulticastWakelockCount--; + if (mWifiMulticastWakelockCount == 0) { mWifiMulticastTimer.stopRunningLocked(elapsedRealtimeMs); StatsLog.write_non_chained( StatsLog.WIFI_MULTICAST_LOCK_STATE_CHANGED, getUid(), null, @@ -7932,7 +7936,7 @@ public class BatteryStatsImpl extends BatteryStats { } if (mWifiMulticastTimer != null) { active |= !mWifiMulticastTimer.reset(false); - active |= mWifiMulticastEnabled; + active |= (mWifiMulticastWakelockCount > 0); } active |= !resetIfNotNull(mAudioTurnedOnTimer, false); @@ -8590,7 +8594,7 @@ public class BatteryStatsImpl extends BatteryStats { mWifiBatchedScanTimer[i] = null; } } - mWifiMulticastEnabled = false; + mWifiMulticastWakelockCount = 0; if (in.readInt() != 0) { mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase, in); @@ -14031,7 +14035,7 @@ public class BatteryStatsImpl extends BatteryStats { u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in); } } - u.mWifiMulticastEnabled = false; + u.mWifiMulticastWakelockCount = 0; if (in.readInt() != 0) { u.mWifiMulticastTimer.readSummaryFromParcelLocked(in); } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 413f89da571e..927322e97e28 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -81,6 +81,8 @@ public final class Zygote { public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ; /** Read-write external storage should be mounted. */ public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE; + /** Read-write external storage should be mounted instead of package sandbox */ + public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL; private static final ZygoteHooks VM_HOOKS = new ZygoteHooks(); diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index b9c717f03749..b60b43a8d45d 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -644,7 +644,9 @@ class ZygoteConnection { mountExternal = Zygote.MOUNT_EXTERNAL_READ; } else if (arg.equals("--mount-external-write")) { mountExternal = Zygote.MOUNT_EXTERNAL_WRITE; - } else if (arg.equals("--query-abi-list")) { + } else if (arg.equals("--mount-external-full")) { + mountExternal = Zygote.MOUNT_EXTERNAL_FULL; + } else if (arg.equals("--query-abi-list")) { abiListQuery = true; } else if (arg.equals("--get-pid")) { pidQuery = true; diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index a79e15a0b7e7..b3af147063d0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -60,7 +60,7 @@ interface IStatusBarService int uid, int initialPid, String message, int userId); void onClearAllNotifications(int userId); void onNotificationClear(String pkg, String tag, int id, int userId, String key, - int dismissalSurface, in NotificationVisibility nv); + int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv); void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys, in NotificationVisibility[] noLongerVisibleKeys); void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded); diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index f76eddf7af14..06726bd753ed 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -30,8 +30,6 @@ import com.android.internal.view.IInputMethodClient; /** * Public interface to the global input method manager, used by all client * applications. - * You need to update BridgeIInputMethodManager.java as well when changing - * this file. */ interface IInputMethodManager { // TODO: Use ParceledListSlice instead diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index c5be8e4a3aba..0a787b99c0ac 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -169,6 +169,10 @@ public class SystemConfig { final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>(); final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppDenyPermissions = + new ArrayMap<>(); + final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); public static SystemConfig getInstance() { @@ -276,6 +280,14 @@ public class SystemConfig { return mProductPrivAppDenyPermissions.get(packageName); } + public ArraySet<String> getProductServicesPrivAppPermissions(String packageName) { + return mProductServicesPrivAppPermissions.get(packageName); + } + + public ArraySet<String> getProductServicesPrivAppDenyPermissions(String packageName) { + return mProductServicesPrivAppDenyPermissions.get(packageName); + } + public Map<String, Boolean> getOemPermissions(String packageName) { final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName); if (oemPermissions != null) { @@ -326,6 +338,17 @@ public class SystemConfig { Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); readPermissions(Environment.buildPath( Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); + + // Allow /product_services to customize system configs around libs, features, permissions + // and apps. + int productServicesPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | + ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS; + readPermissions(Environment.buildPath( + Environment.getProductServicesDirectory(), "etc", "sysconfig"), + productServicesPermissionFlag); + readPermissions(Environment.buildPath( + Environment.getProductServicesDirectory(), "etc", "permissions"), + productServicesPermissionFlag); } void readPermissions(File libraryDir, int permissionFlag) { @@ -659,22 +682,27 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - // privapp permissions from system, vendor and product partitions are stored - // separately. This is to prevent xml files in the vendor partition from - // granting permissions to priv apps in the system partition and vice - // versa. + // privapp permissions from system, vendor, product and product_services + // partitions are stored separately. This is to prevent xml files in the vendor + // partition from granting permissions to priv apps in the system partition and + // vice versa. boolean vendor = permFile.toPath().startsWith( - Environment.getVendorDirectory().toPath()) + Environment.getVendorDirectory().toPath() + "/") || permFile.toPath().startsWith( - Environment.getOdmDirectory().toPath()); + Environment.getOdmDirectory().toPath() + "/"); boolean product = permFile.toPath().startsWith( - Environment.getProductDirectory().toPath()); + Environment.getProductDirectory().toPath() + "/"); + boolean productServices = permFile.toPath().startsWith( + Environment.getProductServicesDirectory().toPath() + "/"); if (vendor) { readPrivAppPermissions(parser, mVendorPrivAppPermissions, mVendorPrivAppDenyPermissions); } else if (product) { readPrivAppPermissions(parser, mProductPrivAppPermissions, mProductPrivAppDenyPermissions); + } else if (productServices) { + readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, + mProductServicesPrivAppDenyPermissions); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 02076bde07f9..8083a6a27da7 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -310,180 +310,17 @@ bool unlockPixels(JNIEnv* env, jobject bitmap) { using namespace android; using namespace android::bitmap; -/////////////////////////////////////////////////////////////////////////////// -// Conversions to/from SkColor, for get/setPixels, and the create method, which -// is basically like setPixels - -typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, - int x, int y); - -static void FromColor_F16(void* dst, const SkColor src[], int width, - int, int) { - uint64_t* d = (uint64_t*)dst; - - for (int i = 0; i < width; i++) { - *d++ = SkColor4f::FromColor(*src++).premul().toF16(); - } -} - -static void FromColor_F16_Raw(void* dst, const SkColor src[], int width, - int, int) { - uint64_t* d = (uint64_t*)dst; - - for (int i = 0; i < width; i++) { - const SkColor4f color = SkColor4f::FromColor(*src++); - uint16_t* scratch = reinterpret_cast<uint16_t*>(d++); - scratch[0] = SkFloatToHalf(color.fR); - scratch[1] = SkFloatToHalf(color.fG); - scratch[2] = SkFloatToHalf(color.fB); - scratch[3] = SkFloatToHalf(color.fA); - } -} - -static void FromColor_D32(void* dst, const SkColor src[], int width, - int, int) { - SkPMColor* d = (SkPMColor*)dst; - - for (int i = 0; i < width; i++) { - *d++ = SkPreMultiplyColor(*src++); - } -} - -static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, - int, int) { - // Needed to thwart the unreachable code detection from clang. - static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER; - - // SkColor's ordering may be different from SkPMColor - if (sk_color_ne_zero) { - memcpy(dst, src, width * sizeof(SkColor)); - return; - } - - // order isn't same, repack each pixel manually - SkPMColor* d = (SkPMColor*)dst; - for (int i = 0; i < width; i++) { - SkColor c = *src++; - *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), - SkColorGetG(c), SkColorGetB(c)); - } -} - -static void FromColor_D565(void* dst, const SkColor src[], int width, - int x, int y) { - uint16_t* d = (uint16_t*)dst; - - DITHER_565_SCAN(y); - for (int stop = x + width; x < stop; x++) { - SkColor c = *src++; - *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), - DITHER_VALUE(x)); - } -} - -static void FromColor_D4444(void* dst, const SkColor src[], int width, - int x, int y) { - SkPMColor16* d = (SkPMColor16*)dst; - - DITHER_4444_SCAN(y); - for (int stop = x + width; x < stop; x++) { - SkPMColor pmc = SkPreMultiplyColor(*src++); - *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); -// *d++ = SkPixel32ToPixel4444(pmc); - } -} - -static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, - int x, int y) { - SkPMColor16* d = (SkPMColor16*)dst; - - DITHER_4444_SCAN(y); - for (int stop = x + width; x < stop; x++) { - SkColor c = *src++; - - // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied - SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), - SkColorGetG(c), SkColorGetB(c)); - *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); -// *d++ = SkPixel32ToPixel4444(pmc); - } -} - -static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) { - uint8_t* d = (uint8_t*)dst; - - for (int stop = x + width; x < stop; x++) { - *d++ = SkColorGetA(*src++); - } -} - -// can return NULL -static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) { - switch (bitmap.colorType()) { - case kN32_SkColorType: - return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw; - case kARGB_4444_SkColorType: - return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 : - FromColor_D4444_Raw; - case kRGB_565_SkColorType: - return FromColor_D565; - case kAlpha_8_SkColorType: - return FromColor_DA8; - case kRGBA_F16_SkColorType: - return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw; - default: - break; - } - return NULL; -} - -static bool IsColorSpaceSRGB(SkColorSpace* colorSpace) { - return colorSpace == nullptr || colorSpace->isSRGB(); -} - bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, - int x, int y, int width, int height, const SkBitmap& dstBitmap) { - void* dst = dstBitmap.getPixels(); - FromColorProc proc = ChooseFromColorProc(dstBitmap); - - if (NULL == dst || NULL == proc) { - return false; - } - + int x, int y, int width, int height, SkBitmap* dstBitmap) { const jint* array = env->GetIntArrayElements(srcColors, NULL); const SkColor* src = (const SkColor*)array + srcOffset; - // reset to to actual choice from caller - dst = dstBitmap.getAddr(x, y); - - SkColorSpace* colorSpace = dstBitmap.colorSpace(); - if (dstBitmap.colorType() == kRGBA_F16_SkColorType || IsColorSpaceSRGB(colorSpace)) { - // now copy/convert each scanline - for (int y = 0; y < height; y++) { - proc(dst, src, width, x, y); - src += srcStride; - dst = (char*)dst + dstBitmap.rowBytes(); - } - } else { - auto sRGB = SkColorSpace::MakeSRGB(); - auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); - - std::unique_ptr<SkColor[]> row(new SkColor[width]); - - // now copy/convert each scanline - for (int y = 0; y < height; y++) { - memcpy(row.get(), src, sizeof(SkColor) * width); - xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), - SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), width, - SkAlphaType::kUnpremul_SkAlphaType); - - proc(dst, row.get(), width, x, y); - src += srcStride; - dst = (char*)dst + dstBitmap.rowBytes(); - } - } + auto sRGB = SkColorSpace::MakeSRGB(); + SkImageInfo srcInfo = SkImageInfo::Make( + width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB); + SkPixmap srcPM(srcInfo, src, srcStride * 4); - dstBitmap.notifyPixelsChanged(); + dstBitmap->writePixels(srcPM, x, y); env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT); return true; @@ -491,90 +328,6 @@ bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int //////////////////// ToColor procs -typedef void (*ToColorProc)(SkColor dst[], const void* src, int width); - -static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - uint64_t* s = (uint64_t*)src; - do { - *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor(); - } while (--width != 0); -} - -static void ToColor_F16_Raw(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - uint64_t* s = (uint64_t*)src; - do { - *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++))); - } while (--width != 0); -} - -static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - *dst++ = SkUnPreMultiply::PMColorToColor(*s++); - } while (--width != 0); -} - -static void ToColor_S32_Raw(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - SkPMColor c = *s++; - *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), - SkGetPackedG32(c), SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - SkPMColor c = *s++; - *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), - SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor16* s = (const SkPMColor16*)src; - do { - *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); - } while (--width != 0); -} - -static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor16* s = (const SkPMColor16*)src; - do { - SkPMColor c = SkPixel4444ToPixel32(*s++); - *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), - SkGetPackedG32(c), SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const SkPMColor16* s = (const SkPMColor16*)src; - do { - SkPMColor c = SkPixel4444ToPixel32(*s++); - *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), - SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S565(SkColor dst[], const void* src, int width) { - SkASSERT(width > 0); - const uint16_t* s = (const uint16_t*)src; - do { - uint16_t c = *s++; - *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), - SkPacked16ToB32(c)); - } while (--width != 0); -} - static void ToColor_SA8(SkColor dst[], const void* src, int width) { SkASSERT(width > 0); const uint8_t* s = (const uint8_t*)src; @@ -584,52 +337,6 @@ static void ToColor_SA8(SkColor dst[], const void* src, int width) { } while (--width != 0); } -// can return NULL -static ToColorProc ChooseToColorProc(const SkBitmap& src) { - switch (src.colorType()) { - case kN32_SkColorType: - switch (src.alphaType()) { - case kOpaque_SkAlphaType: - return ToColor_S32_Opaque; - case kPremul_SkAlphaType: - return ToColor_S32_Alpha; - case kUnpremul_SkAlphaType: - return ToColor_S32_Raw; - default: - return NULL; - } - case kARGB_4444_SkColorType: - switch (src.alphaType()) { - case kOpaque_SkAlphaType: - return ToColor_S4444_Opaque; - case kPremul_SkAlphaType: - return ToColor_S4444_Alpha; - case kUnpremul_SkAlphaType: - return ToColor_S4444_Raw; - default: - return NULL; - } - case kRGB_565_SkColorType: - return ToColor_S565; - case kAlpha_8_SkColorType: - return ToColor_SA8; - case kRGBA_F16_SkColorType: - switch (src.alphaType()) { - case kOpaque_SkAlphaType: - return ToColor_F16_Raw; - case kPremul_SkAlphaType: - return ToColor_F16_Alpha; - case kUnpremul_SkAlphaType: - return ToColor_F16_Raw; - default: - return NULL; - } - default: - break; - } - return NULL; -} - static void ToF16_SA8(void* dst, const void* src, int width) { SkASSERT(width > 0); uint64_t* d = (uint64_t*)dst; @@ -694,7 +401,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, } if (jColors != NULL) { - GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap); + GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap); } return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); @@ -1271,7 +978,7 @@ static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) { if (!bitmapHolder.valid()) return JNI_TRUE; SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); - return IsColorSpaceSRGB(colorSpace); + return colorSpace == nullptr || colorSpace->isSRGB(); } static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) { @@ -1330,28 +1037,13 @@ static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, SkBitmap bitmap; reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); - ToColorProc proc = ChooseToColorProc(bitmap); - if (NULL == proc) { - return 0; - } - const void* src = bitmap.getAddr(x, y); - if (NULL == src) { - return 0; - } - - SkColor dst[1]; - proc(dst, src, 1); + auto sRGB = SkColorSpace::MakeSRGB(); + SkImageInfo dstInfo = SkImageInfo::Make( + 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB); - SkColorSpace* colorSpace = bitmap.colorSpace(); - if (bitmap.colorType() != kRGBA_F16_SkColorType && !IsColorSpaceSRGB(colorSpace)) { - auto sRGB = SkColorSpace::MakeSRGB(); - auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); - xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], - SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1, - SkAlphaType::kUnpremul_SkAlphaType); - } - - return static_cast<jint>(dst[0]); + SkColor dst; + bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y); + return static_cast<jint>(dst); } static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, @@ -1360,41 +1052,12 @@ static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, SkBitmap bitmap; reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); - ToColorProc proc = ChooseToColorProc(bitmap); - if (NULL == proc) { - return; - } - const void* src = bitmap.getAddr(x, y); - if (NULL == src) { - return; - } + auto sRGB = SkColorSpace::MakeSRGB(); + SkImageInfo dstInfo = SkImageInfo::Make( + width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB); jint* dst = env->GetIntArrayElements(pixelArray, NULL); - SkColor* d = (SkColor*)dst + offset; - - SkColorSpace* colorSpace = bitmap.colorSpace(); - if (bitmap.colorType() == kRGBA_F16_SkColorType || IsColorSpaceSRGB(colorSpace)) { - while (--height >= 0) { - proc(d, src, width); - d += stride; - src = (void*)((const char*)src + bitmap.rowBytes()); - } - } else { - auto sRGB = SkColorSpace::MakeSRGB(); - auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); - - while (--height >= 0) { - proc(d, src, width); - - xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d, - SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width, - SkAlphaType::kUnpremul_SkAlphaType); - - d += stride; - src = (void*)((const char*)src + bitmap.rowBytes()); - } - } - + bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y); env->ReleaseIntArrayElements(pixelArray, dst, 0); } @@ -1405,26 +1068,13 @@ static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, SkBitmap bitmap; reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); SkColor color = static_cast<SkColor>(colorHandle); - if (NULL == bitmap.getPixels()) { - return; - } - FromColorProc proc = ChooseFromColorProc(bitmap); - if (NULL == proc) { - return; - } - - SkColorSpace* colorSpace = bitmap.colorSpace(); - if (bitmap.colorType() != kRGBA_F16_SkColorType && !IsColorSpaceSRGB(colorSpace)) { - auto sRGB = SkColorSpace::MakeSRGB(); - auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); - xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, - SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1, - SkAlphaType::kUnpremul_SkAlphaType); - } + auto sRGB = SkColorSpace::MakeSRGB(); + SkImageInfo srcInfo = SkImageInfo::Make( + 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB); + SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes()); - proc(bitmap.getAddr(x, y), &color, 1, x, y); - bitmap.notifyPixelsChanged(); + bitmap.writePixels(srcPM, x, y); } static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, @@ -1433,7 +1083,7 @@ static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, SkBitmap bitmap; reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); GraphicsJNI::SetPixels(env, pixelArray, offset, stride, - x, y, width, height, bitmap); + x, y, width, height, &bitmap); } static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 9d85cc25b6b0..cee3c46dd67f 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -102,7 +102,7 @@ public: */ static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset, int srcStride, int x, int y, int width, int height, - const SkBitmap& dstBitmap); + SkBitmap* dstBitmap); static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams); static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50); diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index db3bfe6e8157..eba4c50b0855 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -462,7 +462,7 @@ static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, return; } - if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) { + if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, &bitmap)) { return; } diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 823f1cc36225..9b138ebb760a 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -323,6 +323,55 @@ static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jin return (jboolean) !queryUserAccess(uid, netId); } +static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst) +{ + if (env->GetArrayLength(addr) != len) { + return false; + } + env->GetByteArrayRegion(addr, 0, len, reinterpret_cast<jbyte*>(dst)); + return true; +} + +static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr, + jbyteArray ipv4Addr, jstring ifname, jobject javaFd) +{ + struct arpreq req = {}; + struct sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa); + struct sockaddr& ethAddrStruct = req.arp_ha; + + ethAddrStruct.sa_family = ARPHRD_ETHER; + if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) { + jniThrowException(env, "java/io/IOException", "Invalid ethAddr length"); + return; + } + + netAddrStruct.sin_family = AF_INET; + if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) { + jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length"); + return; + } + + int ifLen = env->GetStringLength(ifname); + // IFNAMSIZ includes the terminating NULL character + if (ifLen >= IFNAMSIZ) { + jniThrowException(env, "java/io/IOException", "ifname too long"); + return; + } + env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev); + + req.arp_flags = ATF_COM; // Completed entry (ha valid) + int fd = jniGetFDFromFileDescriptor(env, javaFd); + if (fd < 0) { + jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor"); + return; + } + // See also: man 7 arp + if (ioctl(fd, SIOCSARP, &req)) { + jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno)); + return; + } +} + // ---------------------------------------------------------------------------- @@ -337,6 +386,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess }, + { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) android_net_utils_addArpEntry }, { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter }, { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter }, { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter }, diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index fa9f44557d3f..830ca832fb95 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -179,6 +179,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR; } + if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 19691e2cfbe3..364393e1c649 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -93,6 +93,7 @@ enum MountExternalKind { MOUNT_EXTERNAL_DEFAULT = 1, MOUNT_EXTERNAL_READ = 2, MOUNT_EXTERNAL_WRITE = 3, + MOUNT_EXTERNAL_FULL = 4, }; static void RuntimeAbort(JNIEnv* env, int line, const char* msg) { @@ -416,7 +417,7 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, storageSource = "/mnt/runtime/read"; } else if (mount_mode == MOUNT_EXTERNAL_WRITE) { storageSource = "/mnt/runtime/write"; - } else if (!force_mount_namespace) { + } else if (mount_mode != MOUNT_EXTERNAL_FULL && !force_mount_namespace) { // Sane default of no storage visible return true; } @@ -433,19 +434,44 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, } if (GetBoolProperty(kIsolatedStorage, false)) { - if (package_name == nullptr) { - return true; - } - - std::string pkgSandboxDir("/mnt/user"); - if (!createPkgSandbox(uid, package_name, pkgSandboxDir, error_msg)) { - return false; - } - if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage", - nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) { - *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s", - pkgSandboxDir.c_str(), strerror(errno)); - return false; + if (mount_mode == MOUNT_EXTERNAL_FULL) { + storageSource = "/mnt/runtime/write"; + if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", + NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) { + *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s", + storageSource.string(), + strerror(errno)); + return false; + } + + // Mount user-specific symlink helper into place + userid_t user_id = multiuser_get_user_id(uid); + const String8 userSource(String8::format("/mnt/user/%d", user_id)); + if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) { + *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string()); + return false; + } + if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self", + NULL, MS_BIND, NULL)) == -1) { + *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s", + userSource.string(), + strerror(errno)); + return false; + } + } else { + if (package_name == nullptr) { + return true; + } + std::string pkgSandboxDir("/mnt/user"); + if (!createPkgSandbox(uid, package_name, pkgSandboxDir, error_msg)) { + return false; + } + if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage", + nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) { + *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s", + pkgSandboxDir.c_str(), strerror(errno)); + return false; + } } } else { if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index c5904e0e9e5e..f56f7eca5f00 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -87,13 +87,17 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; static const char* kSystemProductOverlayDir = "/system/product/overlay/"; static const char* kProductOverlayDir = "/product/overlay"; + static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/"; + static const char* kProductServicesOverlayDir = "/product_services/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) || android::base::StartsWith(path, kOverlaySubdir) || android::base::StartsWith(path, kVendorOverlayDir) || android::base::StartsWith(path, kSystemProductOverlayDir) - || android::base::StartsWith(path, kProductOverlayDir)) + || android::base::StartsWith(path, kProductOverlayDir) + || android::base::StartsWith(path, kSystemProductServicesOverlayDir) + || android::base::StartsWith(path, kProductServicesOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 703ecf7fba3a..e136d2e3eb17 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Liggaamsensors"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang te verkry tot sensordata oor jou lewenstekens"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot sensordata oor jou lewenstekens?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musiek"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"toegang tot jou musiek"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot jou musiek?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Foto\'s en video\'s"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"toegang tot jou foto\'s en video\'s"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Gee <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> toegang tot jou foto\'s en video\'s?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Venster-inhoud ophaal"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die inhoud ondersoek van \'n venster waarmee jy interaksie het."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Verken deur raak aanskakel"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Laat die program toe om metodes te benut om vingerafdruksjablone vir gebruik by te voeg en uit te vee."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"gebruik vingerafdrukhardeware"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Laat die program toe om vingerafdrukhardeware vir stawing te gebruik"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"lees jou musiekversameling"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Laat die program toe om jou musiekversameling te lees."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"wysig jou musiekversameling"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Laat die program toe om jou musiekversameling te wysig."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"lees jou videoversameling"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Laat die program toe om jou videoversameling te lees."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"wysig jou videoversameling"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Laat die program toe om jou videoversameling te wysig."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"lees jou fotoversameling"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Laat die program toe om jou fotoversameling te lees."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"wysig jou fotoversameling"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Laat die program toe om jou fotoversameling te wysig."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"lees liggings in jou mediaversameling"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Laat die program toe om liggings in jou mediaversameling te lees."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Gedeeltelike vingerafdruk is bespeur. Probeer asseblief weer."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Vingerafdruksensor is vuil. Maak dit skoon en probeer weer."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Stoor <xliff:g id="TYPE">%1$s</xliff:g> in <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Stoor <xliff:g id="TYPE_0">%1$s</xliff:g> en <xliff:g id="TYPE_1">%2$s</xliff:g> in <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Stoor <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> en <xliff:g id="TYPE_2">%3$s</xliff:g> in <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Dateer op na <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Dateer <xliff:g id="TYPE">%1$s</xliff:g> op na <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Dateer <xliff:g id="TYPE_0">%1$s</xliff:g> en <xliff:g id="TYPE_1">%2$s</xliff:g> op na <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Dateer <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> en <xliff:g id="TYPE_2">%3$s</xliff:g> op na <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Stoor"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nee, dankie"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Dateer op"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"wagwoord"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredietkaart"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 0e8aa001e925..10b7da4372bd 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"শৰীৰৰ ছেন্সৰসমূহ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিব পাৰে"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিবলৈ অনুমতি দিবনে?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"সংগীত"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"আপোনাৰ সংগীত এক্সেছ কৰিবলৈ"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ সংগীত এক্সেছ কৰিবলৈ দিবনে?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ফট\' আৰু ভিডিঅ’সমূহ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"আপোনাৰ ফট’ আৰু ভিডিঅ’সমূহ এক্সেছ কৰিবলৈ"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ফিংগাৰপ্ৰিণ্ট টেম্প্লেটসমূহ যোগ কৰা বা মচাৰ পদ্ধতিসমূহ কামত লগাবলৈ নিৰ্দেশ দিবলৈ এপটোক অনুমতি দিয়ে।"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ ব্যৱহাৰ কৰিব পাৰে"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"প্ৰমাণীকৰণৰ বাবে ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰিবলৈ এপটোক অনুমতি দিয়ে"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"নিজৰ সংগীত সংগ্ৰহ পঢ়িবলৈ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"এপক আপোনাৰ সংগীত সংগ্ৰহ পঢ়িবলৈ দিয়ে।"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"আপোনাৰ সংগীত সংগ্ৰহ সালসলনি কৰিবলৈ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"এপক আপোনাৰ সংগীত সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"আপোনাৰ ভিডিঅ’ সংগ্ৰহ পঢ়িবলৈ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"এপক আপোনাৰ ভিডিঅ’ সংগ্ৰহ পঢ়িবলৈ দিয়ে।"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"আপোনাৰ ভিডিঅ’ সংগ্ৰহ সালসলনি কৰিবলৈ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"এপক আপোনাৰ ভিডিঅ’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"আপোনাৰ ফট’ সংগ্ৰহ পঢ়িবলৈ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"এপক আপোনাৰ ফট’ সংগ্ৰহ পঢ়িবলৈ দিয়ে।"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ফিংগাৰপ্ৰিণ্ট আংশিকভাৱে চিনাক্ত কৰা হৈছে। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ফিগাৰপ্ৰিণ্টৰ প্ৰক্ৰিয়া সম্পাদন কৰিবপৰা নগ\'ল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো লেতেৰা হৈ আছে। অনুগ্ৰহ কৰি পৰিষ্কাৰ কৰি আকৌ চেষ্টা কৰক।"</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>ক <b><xliff:g id="LABEL">%2$s</xliff:g></b>ত ছেভ কৰিবনে?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> আৰু <xliff:g id="TYPE_1">%2$s</xliff:g>ক <b><xliff:g id="LABEL">%3$s</xliff:g></b>ত ছেভ কৰিবনে?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, আৰু <xliff:g id="TYPE_2">%3$s</xliff:g>ক <b><xliff:g id="LABEL">%4$s</xliff:g></b>ত ছেভ কৰিবনে?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"আপডে’ট কৰি <b><xliff:g id="LABEL">%1$s</xliff:g></b> বনাবনে?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g>ক আপডে’ট কৰি <b><xliff:g id="LABEL">%2$s</xliff:g></b> বনাবনে?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> আৰু <xliff:g id="TYPE_1">%2$s</xliff:g>ক আপডে’ট কৰি <b><xliff:g id="LABEL">%3$s</xliff:g></b> বনাবনে?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> আৰু <xliff:g id="TYPE_2">%3$s</xliff:g>ক আপডে’ট কৰি to <b><xliff:g id="LABEL">%4$s</xliff:g></b> বনাবনে?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"ছেভ কৰক"</string> <string name="autofill_save_no" msgid="2625132258725581787">"নালাগে, ধন্যবাদ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"আপডে’ট কৰক"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"পাছৱৰ্ড"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ঠিকনা"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ক্ৰেডিট কাৰ্ড"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index dcb7e21e23c9..4d31b1b23c85 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupa podacima senzora o vitalnim funkcijama"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>pristupa podacima senzora o vitalnim funkcijama?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"pristup muzici"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupa muzici?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Slike i video snimci"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"pristup slikama i video snimcima"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Želite li da omogućite da <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristupa slikama i video snimcima?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"da preuzima sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Proverava sadržaj prozora sa kojim ostvarujete interakciju."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"da uključi Istraživanja dodirom"</string> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Dozvoljava aplikaciji da aktivira metode za dodavanje i brisanje šablona otisaka prstiju koji će se koristiti."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"koristi hardver za otiske prstiju"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Dozvoljava aplikaciji da koristi hardver za otiske prstiju radi potvrde autentičnosti"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"čitanje muzičke kolekcije"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Dozvoljava aplikaciji da čita muzičku kolekciju."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"izmena muzičke kolekcije"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Dozvoljava aplikaciji da menja muzičku kolekciju."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"čitanje video kolekcije"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Dozvoljava aplikaciji da čita video kolekciju."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"izmena video kolekcije"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Dozvoljava aplikaciji da menja video kolekciju."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"čitanje kolekcije slika"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Dozvoljava aplikaciji da čita kolekciju slika."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"izmena kolekcije slika"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Dozvoljava aplikaciji da menja kolekciju slika."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz medijske kolekcije"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string> @@ -1947,18 +1927,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Želite li da sačuvate stavku <xliff:g id="TYPE">%1$s</xliff:g> u: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Želite li da sačuvate stavke <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> u: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Želite li da sačuvate stavke <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> u: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Želite li da ažurirate na <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Želite li da ažurirate stavku <xliff:g id="TYPE">%1$s</xliff:g> na <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Želite li da ažurirate stavke <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> na <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Želite li da ažurirate stavke <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> na <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Sačuvaj"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"lozinka"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditna kartica"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 9041156f8aae..77223d7512f1 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Датчыкі цела"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"атрымліваць з датчыка даныя асноўных фізіялагічных паказчыкаў"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Дазволіць праграме <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ да даных з датчыкаў пра вашы асноўныя фізіялагічныя паказчыкі?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"доступ да музыкі"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Дазволіць праграме <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ да музыкі?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Фота і відэа"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"доступ да фота і відэа"</string> + <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> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дазваляе праграме выкарыстоўваць спосабы дадання і выдалення шаблонаў адбіткаў пальцаў для выкарыстання."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"выкарыстоўваць апаратныя сродкі для адбіткаў пальцаў"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дазваляе праграме выкарыстоўваць апаратныя сродкі распазнання адбіткаў пальцаў для аўтэнтыфікацыі"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"паказваць музычную калекцыю"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Праграма зможа паказваць музычную калекцыю."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"змяняць музычную калекцыю"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Праграма зможа змяняць музычную калекцыю."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"паказваць відэакалекцыю"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Праграма зможа паказваць відэакалекцыю."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"змяняць відэакалекцыю"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Праграма зможа змяняць відэакалекцыю."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"паказваць фотакалекцыю"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Праграма зможа паказваць фотакалекцыю."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"змяняць фотакалекцыю"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Праграма зможа змяняць фотакалекцыю."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"паказваць месцазнаходжанне ў калекцыі мультымедыя"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Выяўлена частка адбіткаў пальцаў. Паспрабуйце яшчэ раз."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Датчык адбіткаў пальцаў брудны. Ачысціце яго і паспрабуйце яшчэ раз."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Захаваць <xliff:g id="TYPE">%1$s</xliff:g> у <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Захаваць <xliff:g id="TYPE_0">%1$s</xliff:g> і <xliff:g id="TYPE_1">%2$s</xliff:g> у <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Захаваць <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> і <xliff:g id="TYPE_2">%3$s</xliff:g> у <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Абнавіць у <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Абнавіць <xliff:g id="TYPE">%1$s</xliff:g> у <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Абнавіць <xliff:g id="TYPE_0">%1$s</xliff:g> і <xliff:g id="TYPE_1">%2$s</xliff:g> у <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Абнавіць <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> і <xliff:g id="TYPE_2">%3$s</xliff:g> у <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Захаваць"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Не, дзякуй"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Абнавіць"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"пароль"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"адрас"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"крэдытная картка"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 80c6cebe5eec..3fc31f07f534 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Телесни сензори"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"достъп до сензорните данни за жизнените ви показатели"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Да се разреши ли на <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да осъществява достъп до данните от сензорите за жизнените ви показатели?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музика"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"достъп до музиката ви"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Да се разреши ли на <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> да осъществява достъп до музиката ви?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Снимки и видеоклипове"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"достъп до снимките и видеоклиповете ви"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Разрешава на приложението да извиква начини за добавяне и изтриване на шаблони за отпечатъци, които да се използват."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"използване на хардуера за отпечатъци"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Разрешава на приложението да използва хардуера за отпечатъци с цел удостоверяване"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"да чете музикалната ви колекция"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Разрешава на приложението да чете музикалната ви колекция."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"да променя музикалната ви колекция"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Разрешава на приложението да променя музикалната ви колекция."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"да чете видеоколекцията ви"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Разрешава на приложението да чете видеоколекцията ви."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"да променя видеоколекцията ви"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Разрешава на приложението да променя видеоколекцията ви."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"да чете колекцията ви от снимки"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Разрешава на приложението да чете колекцията ви от снимки."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"да променя колекцията ви от снимки"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Разрешава на приложението да променя колекцията ви от снимки."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"да чете местоположенията от мултимедийната ви колекция"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Открит е частичен отпечатък. Моля, опитайте отново."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Отпечатъкът не можа да се обработи. Моля, опитайте отново."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензорът за отпечатъци е мръсен. Моля, почистете го и опитайте отново."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> да се запази ли в/ъв <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> да се запазят ли в/ъв <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> да се запазят ли в/ъв <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Да се актуализира ли в(ъв) <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> да се актуализира ли в(ъв) <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> да се актуализират ли в(ъв) <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> да се актуализират ли в(ъв) <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Запазване"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Не, благодаря"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Актуализиране"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"Паролата"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"Адресът"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Кредитната карта"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 026a759360f0..e7990ca52991 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"বডি সেন্সরগুলি"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"আপনার অত্যাবশ্যক লক্ষণগুলির সম্পর্কে সেন্সর ডেটা অ্যাক্সেস করে"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-কে সেন্সর থেকে আপনার ভাইটাল সাইনের ডেটা অ্যাক্সেস করতে দেবেন?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"মিউজিক"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"আপনার মিউজিকে অ্যাক্সেস করুন"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-কে আপনার মিউজিকে অ্যাক্সেস দেবেন?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ফটো ও ভিডিও"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"আপনার ফটো ও ভিডিও অ্যাক্সেস করুন"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ব্যবহার করার জন্য আঙ্গুলের ছাপের টেম্প্লেটগুলি যোগ করা এবং মোছার পদ্ধতিগুলি গ্রহন করতে অ্যাপ্লিকেশানটিতে অমুমতি দেয়৷"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার ব্যবহার করুন"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"অনুমোদনের জন্য আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার ব্যবহার করতে অ্যাপ্লিকেশানটিতে অনুমতি দেয়"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"আপনার মিউজিক সংগ্রহ পড়ুন"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"অ্যাপকে আপনার মিউজিক সংগ্রহ পড়ার অনুমতি দিন।"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"আপনার মিউজিক সংগ্রহ পরিবর্তন করুন"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"আপনার মিউজিক সংগ্রহ পরিবর্তন করতে অ্যাপকে অনুমতি দিন।"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"আপনার ভিডিও সংগ্রহ পড়ুন"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"অ্যাপকে আপনার ভিডিও সংগ্রহ দেখার অনুমতি দিন।"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"আপনার ভিডিও সংগ্রহ পরিবর্তন করুন"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"আপনার ভিডিও সংগ্রহ পরিবর্তন করতে অ্যাপকে অনুমতি দিন।"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"আপনার ছবি সংগ্রহ পড়ুন"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"আপনার ফটো সংগ্রহ পড়ার অনুমতি অ্যাপকে দিন।"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"আপনার ফটো সংগ্রহ পরিবর্তন করুন"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ অনুগ্রহ করে পরিষ্কার করে আবার চেষ্টা করুন৷"</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> কে <b><xliff:g id="LABEL">%2$s</xliff:g></b>এ সংরক্ষণ করবেন?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> এবং <xliff:g id="TYPE_1">%2$s</xliff:g> কে <b><xliff:g id="LABEL">%3$s</xliff:g></b> এ সংরক্ষণ করবেন?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, এবং <xliff:g id="TYPE_2">%3$s</xliff:g> কে <b><xliff:g id="LABEL">%4$s</xliff:g></b> এ সংরক্ষণ করবেন?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>-তে আপডেট করতে চান?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> থেকে <b><xliff:g id="LABEL">%2$s</xliff:g></b>-এ আপডেট করতে চান?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> এবং <xliff:g id="TYPE_1">%2$s</xliff:g>o <b><xliff:g id="LABEL">%3$s</xliff:g></b>-এ আপডেট করতে চান?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>,এবং <xliff:g id="TYPE_2">%3$s</xliff:g> to <b><xliff:g id="LABEL">%4$s</xliff:g></b> আপডেট করতে চান?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"সেভ করুন"</string> <string name="autofill_save_no" msgid="2625132258725581787">"না থাক"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"আপডেট করুন"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"পাসওয়ার্ড"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ঠিকানা"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ক্রেডিট কার্ড"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 049b3835e915..244af735a431 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Tjelesni senzori"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupa podacima senzora o vašim vitalnim funkcijama"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pristup senzornim podacima o vašim vitalnim znacima?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"pristup muzici"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>da pristupi vašoj muzici?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotografije i videozapisi"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"pristup fotografijama i videozapisima"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Dozvoliti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupi vašim fotografijama i videozapisima?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Preuzima sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Pregleda sadržaj prozora koji trenutno koristite."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključi opciju Istraživanje dodirom"</string> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Omogućava aplikaciji da koristi metode za dodavanje i brisanje šablona otisaka prstiju za upotrebu."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"korištenje hardvera za otiske prstiju"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Omogućava aplikaciji da za provjeru vjerodostojnosti koristi hardver za otiske prstiju"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"čitanje muzičke kolekcije"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Omogućava aplikaciji da čita vašu muzičku kolekciju."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"izmjena muzičke kolekcije"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Omogućava aplikaciji da mijenja vašu muzičku kolekciju."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"čitanje kolekcije videozapisa"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Omogućava aplikaciji da čita vašu kolekciju videozapisa."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"izmjena kolekcije videozapisa"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Omogućava aplikaciji da mijenja vašu kolekciju videozapisa."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"čitanje kolekcije fotografija"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Omogućava aplikaciji da čita vašu kolekciju fotografija."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"izmjena kolekcije fotografija"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Omogućava aplikaciji da mijenja vašu kolekciju fotografija."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz kolekcije medija"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspjela obrada otiska prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string> @@ -1949,18 +1929,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Želite li da se <xliff:g id="TYPE">%1$s</xliff:g> sačuva u <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> sačuvaju u <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, i <xliff:g id="TYPE_2">%3$s</xliff:g> sačuvaju <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Želite li ažurirati na <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Želite li da se <xliff:g id="TYPE">%1$s</xliff:g> ažurira na <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> ažuriraju na <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, i <xliff:g id="TYPE_2">%3$s</xliff:g> ažuriraju na <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Sačuvaj"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"lozinka"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditna kartica"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index c75fc74ec7ab..2c74e8247852 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensors corporals"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedir a les dades del sensor sobre els signes vitals"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi a les dades del sensor de constants vitals?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Música"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"accedir a la teva música"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi a la teva música?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotos i vídeos"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"accedir a les teves fotos i als teus vídeos"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi a les teves fotos i als teus vídeos?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar el contingut de la finestra"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecciona el contingut d\'una finestra amb què estàs interaccionant."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activar Exploració tàctil"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet que l\'aplicació invoqui mètodes per afegir i suprimir plantilles d\'empremtes digitals que es puguin fer servir."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilitzar el maquinari d\'empremtes digitals"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet que l\'aplicació faci servir maquinari d\'empremtes digitals per a l\'autenticació"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"llegir la teva col·lecció de música"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Permet que l\'aplicació llegeixi la teva col·lecció de música."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modificar la teva col·lecció de música"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Permet que l\'aplicació modifiqui la teva col·lecció de música."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"llegir la teva col·lecció de vídeos"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Permet que l\'aplicació llegeixi la teva col·lecció de vídeos."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modificar la teva col·lecció de vídeos"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Permet que l\'aplicació modifiqui la teva col·lecció de vídeos."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"llegir la teva col·lecció de fotos"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Permet que l\'aplicació llegeixi la teva col·lecció de fotos."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modificar la teva col·lecció de fotos"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permet que l\'aplicació modifiqui la teva col·lecció de fotos."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"llegir les ubicacions de les teves col·leccions multimèdia"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor d\'empremtes digitals està brut. Neteja\'l i torna-ho a provar."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vols desar <xliff:g id="TYPE">%1$s</xliff:g> a <xliff:g id="LABEL">%2$s</xliff:g>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vols desar <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="LABEL">%3$s</xliff:g>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vols desar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> a <xliff:g id="LABEL">%4$s</xliff:g>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Vols actualitzar les dades a <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Vols actualitzar <xliff:g id="TYPE">%1$s</xliff:g> a <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Vols actualitzar <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Vols actualitzar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> a <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Desa"</string> <string name="autofill_save_no" msgid="2625132258725581787">"No, gràcies"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Actualitza"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"contrasenya"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adreça"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"targeta de crèdit"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 7d9c3c593803..278ab95706c4 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Tělesné senzory"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"přístup k datům ze snímačů vašich životních funkcí"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup k údajům ze snímačů vašich životních funkcí?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Hudba"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"přístup k hudbě"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup k hudbě?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotky a videa"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"přístup k fotkám a videím"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Povolit aplikaci <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> přístup k fotkám a videím?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Načítat obsah oken"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Může prozkoumávat obsah oken, se kterými pracujete."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Zapnout funkci Prozkoumání dotykem"</string> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Umožňuje aplikaci volat metody k přidání a smazání šablon otisků prstů, které budou použity."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"použití hardwaru na čtení otisků prstů"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Umožňuje aplikaci použít k ověření hardware na čtení otisků prstů"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"čtení hudební sbírky"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Umožňuje aplikaci číst vaši hudební sbírku."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"úprava hudební sbírky"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Umožňuje aplikaci upravit vaši hudební sbírku."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"čtení sbírky videí"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Umožňuje aplikaci číst vaši sbírku videí."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"úprava sbírky videí"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Umožňuje aplikaci upravit vaši sbírku videí."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"čtení sbírky fotek"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Umožňuje aplikaci číst vaši sbírku fotek."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"úprava sbírky fotek"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Umožňuje aplikaci upravit vaši sbírku fotek."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"čtení míst ze sbírky médií"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Byla zjištěna jen část otisku prstu. Zkuste to znovu."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otisků prstů je znečištěn. Vyčistěte jej a zkuste to znovu."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Uložit položku <xliff:g id="TYPE">%1$s</xliff:g> do služby <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Uložit položky <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> do služby <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Uložit položky <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g> do služby <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Aktualizovat službu <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Aktualizovat položku <xliff:g id="TYPE">%1$s</xliff:g> ve službě <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Aktualizovat položky <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> ve službě <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Aktualizovat položky <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g> ve službě <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Uložit"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ne, děkuji"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Aktualizovat"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"heslo"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"platební karta"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 909cd10721c6..32be0d34f57d 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Kropssensorer"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"få adgang til sensordata om dine livstegn"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til sensordata om dine livstegn?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"adgang til din musik"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til din musik?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Billeder og videoer"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"adgang til dine billeder og videoer"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vil du give <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til dine billeder og videoer?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Hente indholdet i vinduet"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Undersøge indholdet i et vindue, du interagerer med."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktivere Udforsk ved berøring"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Tillader, at appen kan køre metoder til at tilføje og slette fingeraftryksskabeloner"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"bruge fingeraftrykhardware"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Tillader, at appen kan bruge fingeraftrykhardware til godkendelse"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"læse din musiksamling"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Tillader, at appen kan læse din musiksamling."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ændre din musiksamling"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Tillader, at appen kan ændre din musiksamling."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"læse din videosamling"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Tillader, at appen kan læse din videosamling."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ændre din videosamling"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Tillader, at appen kan ændre din videosamling."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"læse din billedsamling"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Tillader, at appen kan læse din billedsamling."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ændre din billedsamling"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Tillader, at appen kan ændre din billedsamling."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"læse placeringer fra din mediesamling"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillader, at appen kan læse placeringer fra din mediesamling."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Der blev registreret et delvist fingeraftryk. Prøv igen."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensoren til registrering af fingeraftryk er beskidt. Tør den af, og prøv igen."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vil du gemme <xliff:g id="TYPE">%1$s</xliff:g> i <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vil du gemme <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> i <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vil du gemme <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> i <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Vil du opdatere til <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Vil du opdatere <xliff:g id="TYPE">%1$s</xliff:g> til <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Vil du opdatere <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> til <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Vil du opdatere <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> til <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Gem"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nej tak"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Opdater"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"adgangskode"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkort"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index e8434887ed0a..e5b9372d25cf 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Körpersensoren"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"auf Sensordaten zu deinen Vitaldaten zugreifen"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> erlauben, auf Sensordaten zu deinen Vitalfunktionen zuzugreifen?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"auf Musik zugreifen"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> Zugriff auf deine Musik gewähren?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotos und Videos"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"auf meine Fotos und Videos zugreifen"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> Zugriff auf deine Fotos und Videos gewähren?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Fensterinhalte abrufen"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\"Tippen & Entdecken\" aktivieren"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erlaubt der App, Methoden zum Hinzufügen und Löschen zu verwendender Fingerabdruckvorlagen aufzurufen"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"Fingerabdruckhardware verwenden"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Erlaubt der App, Fingerabdruckhardware zur Authentifizierung zu verwenden"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"meine Musiksammlung abrufen"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Ermöglicht der App, deine Musiksammlung abzurufen."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"meine Musiksammlung ändern"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Ermöglicht der App, deine Musiksammlung zu ändern."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"meine Videosammlung abrufen"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Ermöglicht der App, deine Videosammlung abzurufen."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"meine Videosammlung ändern"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Ermöglicht der App, deine Videosammlung zu ändern."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"meine Fotosammlung abrufen"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Ermöglicht der App, deine Fotosammlung abzurufen."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"meine Fotosammlung ändern"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ermöglicht der App, deine Fotosammlung zu ändern."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"Standorte aus meiner Mediensammlung abrufen"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuche es erneut."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuche es erneut."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es erneut."</string> @@ -625,13 +605,13 @@ <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string> - <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string> + <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Eigentümer, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsproviderdienst binden"</string> - <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Eigentümer, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="permlab_bindDreamService" msgid="4153646965978563462">"An Dream-Dienst binden"</string> <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Ermöglicht der App, sich an die Oberfläche eines Dream-Dienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string> - <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Eigentümer, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Kalibrierung für Eingabegerät ändern"</string> @@ -643,9 +623,9 @@ <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM-Zertifikate entfernen"</string> <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ermöglicht einer App das Entfernen von DRM-Zertifikaten. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"An einen Mobilfunkanbieter-Messaging-Dienst binden"</string> - <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ermöglicht dem Inhaber die Bindung an die Oberfläche eines Mobilfunkanbieter-Messaging-Dienstes auf oberster Ebene. Für normale Apps sollte dies nie erforderlich sein."</string> + <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ermöglicht dem Eigentümer die Bindung an die Oberfläche eines Mobilfunkanbieter-Messaging-Dienstes auf oberster Ebene. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"An Mobilfunkanbieter-Dienste binden"</string> - <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Ermöglicht dem Inhaber die Bindung an Mobilfunkanbieter-Dienste. Für normale Apps sollte dies nicht erforderlich sein."</string> + <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Ermöglicht dem Eigentümer die Bindung an Mobilfunkanbieter-Dienste. Für normale Apps sollte dies nicht erforderlich sein."</string> <string name="permlab_access_notification_policy" msgid="4247510821662059671">"Auf \"Nicht stören\" zugreifen"</string> <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ermöglicht der App Lese- und Schreibzugriff auf die \"Nicht stören\"-Konfiguration"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> in <b><xliff:g id="LABEL">%2$s</xliff:g></b> speichern?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> und <xliff:g id="TYPE_1">%2$s</xliff:g> in <b><xliff:g id="LABEL">%3$s</xliff:g></b> speichern?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> und <xliff:g id="TYPE_2">%3$s</xliff:g> in <b><xliff:g id="LABEL">%4$s</xliff:g></b> speichern?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Über <b><xliff:g id="LABEL">%1$s</xliff:g></b> aktualisieren?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> über <b><xliff:g id="LABEL">%2$s</xliff:g></b> aktualisieren?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> und <xliff:g id="TYPE_1">%2$s</xliff:g> über <b><xliff:g id="LABEL">%3$s</xliff:g></b> aktualisieren?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> und <xliff:g id="TYPE_2">%3$s</xliff:g> über <b><xliff:g id="LABEL">%4$s</xliff:g></b> aktualisieren?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Speichern"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nein danke"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Aktualisieren"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"Passwort"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"Adresse"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Kreditkarte"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index ef8b072c476b..482e29f39715 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Αισθητήρες σώματος"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> να έχει πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας;"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Μουσική"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"πρόσβαση στη μουσική σας"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Να επιτρέπεται στην εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> να έχει πρόσβαση στη μουσική σας;"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Φωτογραφίες και βίντεο"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"πρόσβαση στις φωτογραφίες και στα βίντεό σας"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους για την προσθήκη και τη διαγραφή προτύπων μοναδικού χαρακτηριστικού για χρήση."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρησιμοποιεί τον εξοπλισμό δακτυλικού αποτυπώματος"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί εξοπλισμό μοναδικού χαρακτηριστικού για έλεγχο ταυτότητας"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ανάγνωση της μουσικής συλλογής σας"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Επιτρέπει στην εφαρμογή να διαβάσει τη μουσική συλλογή σας."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"τροποποίηση της μουσικής συλλογής σας"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη μουσική συλλογή σας."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ανάγνωση της συλλογής βίντεό σας"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Επιτρέπει στην εφαρμογή να διαβάσει τη συλλογή βίντεό σας."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"τροποποίηση της συλλογής βίντεό σας"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή βίντεό σας."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ανάγνωση της συλλογής φωτογραφιών σας"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Επιτρέπει στην εφαρμογή να διαβάσει τη συλλογή φωτογραφιών σας."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"τροποποίηση της συλλογής φωτογραφιών σας"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή φωτογραφιών σας."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ανάγνωση τοποθεσιών από τη συλλογή πολυμέσων σας"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Εντοπίστηκε μερικό μοναδικό χαρακτηριστικό. Δοκιμάστε ξανά."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Δεν ήταν δυνατή η επεξεργασία του μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Ο αισθητήρας μοναδικού χαρακτηριστικού δεν είναι καθαρός. Καθαρίστε τον και δοκιμάστε ξανά."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Αποθήκευση <xliff:g id="TYPE">%1$s</xliff:g> σε <b><xliff:g id="LABEL">%2$s</xliff:g></b>;"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Αποθήκευση <xliff:g id="TYPE_0">%1$s</xliff:g> και <xliff:g id="TYPE_1">%2$s</xliff:g> σε <b><xliff:g id="LABEL">%3$s</xliff:g></b>;"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Αποθήκευση <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> και <xliff:g id="TYPE_2">%3$s</xliff:g> σε <b><xliff:g id="LABEL">%4$s</xliff:g></b>;"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Να γίνει ενημέρωση στο <b><xliff:g id="LABEL">%1$s</xliff:g></b>;"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Να γίνει ενημέρωση των δεδομένων <xliff:g id="TYPE">%1$s</xliff:g> στην υπηρεσία <b><xliff:g id="LABEL">%2$s</xliff:g></b>;"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Να γίνει ενημέρωση των δεδομένων <xliff:g id="TYPE_0">%1$s</xliff:g> και <xliff:g id="TYPE_1">%2$s</xliff:g> στην υπηρεσία <b><xliff:g id="LABEL">%3$s</xliff:g></b>;"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Να γίνει ενημέρωση των δεδομένων <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> και <xliff:g id="TYPE_2">%3$s</xliff:g> στην υπηρεσία <b><xliff:g id="LABEL">%4$s</xliff:g></b>;"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Αποθήκευση"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Όχι, ευχαριστώ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Ενημέρωση"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"κωδικός πρόσβασης"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"διεύθυνση"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"πιστωτική κάρτα"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 55e05261f502..5e6c8fa0edce 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporales"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder a datos de sensores de tus constantes vitales"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"¿Quieres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a los datos del sensor sobre tus constantes vitales?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Música"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"acceder a tu música"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"¿Quieres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a tu música?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotos y vídeos"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"acceder a tus fotos y vídeos"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"¿Quieres permitir que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda a tus fotos y vídeos?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Comprobar el contenido de la ventana"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecciona el contenido de una ventana con la que estés interactuando."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activar la exploración táctil"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación invoque métodos para añadir y eliminar plantillas de huellas digitales y utilizarlas."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizar hardware de huellas digitales"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"leer tu colección de música"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Permite que la aplicación lea tu colección de música."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modificar tu colección de música"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Permite que la aplicación modifique tu colección de música."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"leer tu colección de vídeos"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Permite que la aplicación lea tu colección de vídeos."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modificar tu colección de vídeos"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Permite que la aplicación modifique tu colección de vídeos."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"leer tu colección de fotos"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Permite que la aplicación lea tu colección de fotos."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modificar tu colección de fotos"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que la aplicación modifique tu colección de fotos."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"leer las ubicaciones de tu colección de contenido multimedia"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Se ha detectado una huella digital parcial. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor de huellas digitales está sucio. Límpialo y vuelve a intentarlo."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"¿Guardar <xliff:g id="TYPE">%1$s</xliff:g> en <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"¿Guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"¿Guardar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> y <xliff:g id="TYPE_2">%3$s</xliff:g> en <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"¿Quieres actualizar a <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"¿Quieres actualizar <xliff:g id="TYPE">%1$s</xliff:g> a <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"¿Quieres actualizar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> a <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"¿Quieres actualizar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> y <xliff:g id="TYPE_2">%3$s</xliff:g> a <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Guardar"</string> <string name="autofill_save_no" msgid="2625132258725581787">"No, gracias"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Actualizar"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"contraseña"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"dirección"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"tarjeta de crédito"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 758bf4409a58..56181c864e08 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Kehaandurid"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"juurdepääs anduri andmetele teie eluliste näitajate kohta"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Kas lubada rakendusele <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> juurdepääs anduri andmetele teie eluliste näitajate kohta?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muusika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"Pääseda juurde teie muusikale"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Kas lubada rakendusele <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> juurdepääs teie muusikale?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotod ja videod"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"Pääseda juurde teie fotodele ja videotele"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Kas lubada rakendusele <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> juurdepääs teie fotodele ja videotele?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Akna sisu toomine"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Kasutatava akna sisu kontrollimine."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Puudutusega sirvimise sisselülitamine"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Võimaldab rakendusel tühistada meetodid kasutatavate sõrmejäljemallide lisamiseks ja kustutamiseks."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"sõrmejälje riistvara kasutamine"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Võimaldab rakendusel autentimiseks kasutada sõrmejälje riistvara"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"Lugeda teie muusikakogu"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Võimaldab rakendusel lugeda teie muusikakogu."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"Muuta teie muusikakogu"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Võimaldab rakendusel muuta teie muusikakogu."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"Lugeda teie videokogu"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Võimaldab rakendusel lugeda teie videokogu."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"Muuta teie videokogu"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Võimaldab rakendusel muuta teie videokogu."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"Lugeda teie fotokogu"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Võimaldab rakendusel lugeda teie fotokogu."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"Muuta teie fotokogu"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Võimaldab rakendusel muuta teie fotokogu."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"Lugeda teie meediakogus olevaid asukohti"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Tuvastati osaline sõrmejälg. Proovige uuesti."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sõrmejäljeandur on must. Puhastage see ja proovige uuesti."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Kas salvestada üksus <xliff:g id="TYPE">%1$s</xliff:g> teenusesse <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Kas salvestada üksused <xliff:g id="TYPE_0">%1$s</xliff:g> ja <xliff:g id="TYPE_1">%2$s</xliff:g> teenusesse <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Kas salvestada üksused <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ja <xliff:g id="TYPE_2">%3$s</xliff:g> teenusesse <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Kas värskendada valikule <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Kas värskendada üksus <xliff:g id="TYPE">%1$s</xliff:g> valikule <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Kas värskendada üksused <xliff:g id="TYPE_0">%1$s</xliff:g> ja <xliff:g id="TYPE_1">%2$s</xliff:g> valikule <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Kas värskendada üksused <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ja <xliff:g id="TYPE_2">%3$s</xliff:g> valikule <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Salvesta"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Tänan, ei"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Värskenda"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"parool"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"aadress"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"krediitkaart"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 567ca1863d8e..5ec56376c0c8 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Gorputz-sentsoreak"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"atzitu bizi-konstanteei buruzko sentsorearen datuak"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Bizi-konstanteei buruzko sentsorearen datuak atzitzea baimendu nahi diozu <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"musika atzitu"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari musika atzitzea baimendu nahi diozu?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Argazkiak eta bideoak"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"argazkiak eta bideoak atzitu"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari argazkiak eta bideoak atzitzea baimendu nahi diozu?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu \"Arakatu ukituta\""</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erreferentzia-gako digitalen txantiloiak gehitzeko eta ezabatzeko metodoei dei egitea baimentzen die aplikazioei."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"erabili erreferentzia-gako digitalen hardwarea"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autentifikatzeko erreferentzia-gako digitalen hardwarea erabiltzea baimentzen die aplikazioei."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"musika-bilduma irakurri"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Musika-bilduma irakurtzea baimentzen die aplikazioei."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"musika-bilduma aldatu"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Musika-bilduma aldatzea baimentzen die aplikazioei."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"bideo-bilduma irakurri"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Bideo-bilduma irakurtzea baimentzen die aplikazioei."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"bideo-bilduma aldatu"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Bideo-bilduma aldatzea baimentzen die aplikazioei."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"argazki-bilduma irakurri"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Argazki-bilduma irakurtzea baimentzen die aplikazioei."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"argazki-bilduma aldatu"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Argazki-bilduma aldatzea baimentzen die aplikazioei."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"multimedia-edukien bildumako kokapena irakurri"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Multimedia-edukien bildumako kokapena irakurtzea baimentzen die aplikazioei."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hatz-marka digitala ez da osorik hauteman. Saiatu berriro."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Hatz-marka digitalen sentsorea zikina dago. Garbi ezazu, eta saiatu berriro."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> zerbitzuan gorde nahi duzu?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> eta <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> zerbitzuan gorde nahi dituzu?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> eta <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> zerbitzuan gorde nahi dituzu?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> zerbitzuan eguneratu nahi duzu?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> zerbitzuan eguneratu nahi duzu?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> eta <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> zerbitzuan eguneratu nahi dituzu?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> eta <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> zerbitzuan eguneratu nahi dituzu?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Gorde"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ez, eskerrik asko"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Eguneratu"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"pasahitza"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"helbidea"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditu-txartela"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index fda01a05ab75..240920295501 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -304,8 +304,8 @@ <string name="permgroupdesc_aural" msgid="4870189506255958055">"accéder à votre musique"</string> <string name="permgrouprequest_aural" msgid="6787926123071735620">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à votre musique?"</string> <string name="permgrouplab_visual" msgid="8030190588123857921">"Photos et vidéos"</string> - <string name="permgroupdesc_visual" msgid="3415827902566663546">"accéder à vos photos et vos vidéos"</string> - <string name="permgrouprequest_visual" msgid="6907523945030290376">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à vos photos et vos videos?"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"accéder à vos photos et à vos vidéos"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à vos photos et à vos videos?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Récupérer le contenu d\'une fenêtre"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecter le contenu d\'une fenêtre avec laquelle vous interagissez."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activer la fonctionnalité Explorer au toucher"</string> @@ -501,19 +501,19 @@ <string name="permlab_useFingerprint" msgid="3150478619915124905">"utiliser le matériel d\'empreinte digitale"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet à l\'application d\'utiliser du matériel d\'empreinte digitale pour l\'authentification"</string> <string name="permlab_audioRead" msgid="6617225220728465565">"lire votre collection de musique"</string> - <string name="permdesc_audioRead" msgid="5034032570243484805">"Autoriser l\'application à lire votre collection de musique."</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Autorise l\'application à lire votre collection de musique."</string> <string name="permlab_audioWrite" msgid="2661772059799779292">"modifier votre collection de musique"</string> - <string name="permdesc_audioWrite" msgid="8888544708166230494">"Autoriser l\'application à modifier votre collection de musique."</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Autorise l\'application à modifier votre collection de musique."</string> <string name="permlab_videoRead" msgid="9182618678674737229">"lire votre collection de vidéos"</string> - <string name="permdesc_videoRead" msgid="7045676429859396194">"Autoriser l\'application à lire votre collection de vidéos."</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Autorise l\'application à lire votre collection de vidéos."</string> <string name="permlab_videoWrite" msgid="128769316366746446">"modifier votre collection de vidéos"</string> - <string name="permdesc_videoWrite" msgid="5448565757490640841">"Autoriser l\'application à modifier votre collection de vidéos."</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Autorise l\'application à modifier votre collection de vidéos."</string> <string name="permlab_imagesRead" msgid="3015078545742665304">"lire votre collection de photos"</string> - <string name="permdesc_imagesRead" msgid="3144263806038695580">"Autoriser l\'application à lire votre collection de photos."</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Autorise l\'application à lire votre collection de photos."</string> <string name="permlab_imagesWrite" msgid="3391306186247235510">"modifier votre collection de photos"</string> - <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Autoriser l\'application à modifier votre collection de photos."</string> - <string name="permlab_mediaLocation" msgid="8675148183726247864">"lire les positions indiquées dans votre collection multimédia"</string> - <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autoriser l\'application à lire les positions indiquées dans votre collection multimédia."</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Autorise l\'application à modifier votre collection de photos."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"lire les positions issues de votre collection multimédia"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte digitale partielle détectée. Veuillez essayer de nouveau."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de traiter les empreintes digitales. Veuillez essayer de nouveau."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le capteur d\'empreintes digitales est sale. Veuillez le nettoyer et essayer de nouveau."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 94d33db84a1e..9c8a7e78bca0 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Capteurs corporels"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accéder aux données des capteurs relatives à vos signes vitaux"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder aux données des capteurs relatives à vos signes vitaux ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musique"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"accéder à votre musique"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à votre musique ?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Photos et vidéos"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"accéder à vos photos et vos vidéos"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder à vos photos et vidéos ?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Récupérer le contenu d\'une fenêtre"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecte le contenu d\'une fenêtre avec laquelle vous interagissez."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activer la fonctionnalité Explorer au toucher"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Autoriser l\'application à invoquer des méthodes pour ajouter et supprimer des modèles d\'empreintes digitales"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utiliser le matériel d\'empreintes digitales"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autoriser l\'application à utiliser le matériel d\'empreintes digitales pour l\'authentification"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"consulter votre bibliothèque musicale"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Autorise l\'application à consulter votre bibliothèque musicale."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modifier votre bibliothèque musicale"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Autorise l\'application à modifier votre bibliothèque musicale."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"consulter votre bibliothèque vidéo"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Autorise l\'application à consulter votre bibliothèque vidéo."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modifier votre bibliothèque vidéo"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Autorise l\'application à modifier votre bibliothèque vidéo."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"consulter votre bibliothèque photo"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Autorise l\'application à consulter votre bibliothèque photo."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modifier votre bibliothèque photo"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Autorise l\'application à modifier votre bibliothèque photo."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"consulter des positions issues de votre bibliothèque multimédia"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte numérique partiellement détectée. Veuillez réessayer."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de reconnaître l\'empreinte numérique. Veuillez réessayer."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le lecteur d\'empreintes numériques est sale. Veuillez le nettoyer, puis réessayer."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Enregistrer <xliff:g id="TYPE">%1$s</xliff:g> dans <b><xliff:g id="LABEL">%2$s</xliff:g></b> ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans <b><xliff:g id="LABEL">%3$s</xliff:g></b> ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g> dans <b><xliff:g id="LABEL">%4$s</xliff:g></b> ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Faire passer à <b><xliff:g id="LABEL">%1$s</xliff:g></b> ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Faire passer <xliff:g id="TYPE">%1$s</xliff:g> à <b><xliff:g id="LABEL">%2$s</xliff:g></b> ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Faire passer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> à <b><xliff:g id="LABEL">%3$s</xliff:g></b> ?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Faire passer <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g> à <b><xliff:g id="LABEL">%4$s</xliff:g></b> ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Enregistrer"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Non, merci"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Mettre à jour"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"mot de passe"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"carte de paiement"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index a32a36e75d69..27efff880db5 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder aos datos do sensor sobre as túas constantes vitais"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda aos datos do sensor sobre as túas constantes vitais?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Música"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"acceder á música"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda á túa música?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotos e vídeos"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"acceder ás fotos e aos vídeos"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda ás túas fotos e vídeos?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar contido da ventá"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecciona o contido dunha ventá coa que estás interactuando."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activar a exploración táctil"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que a aplicación invoque métodos para engadir e eliminar modelos de uso de impresión dixital."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"usar hardware de impresión dixital"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que a aplicación utilice hardware de impresión dixital para a autenticación"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ler a túa colección de música"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Permite que a aplicación lea a túa colección de música."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modificar a túa colección de música"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Permite que a aplicación modifique a túa colección de música."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ler a túa colección de vídeos"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Permite que a aplicación lea a túa colección de vídeos."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modificar a túa colección de vídeos"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Permite que a aplicación modifique a túa colección de vídeos."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ler a túa colección de fotos"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Permite que a aplicación lea a túa colección de fotos."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modificar a túa colección de fotos"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que a aplicación modifique a túa colección de fotos."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ler localizacións da túa colección multimedia"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Detectouse unha impresión dixital parcial. Téntao de novo."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Non se puido procesar a impresión dixital. Téntao de novo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impresión dixital está sucio. Límpao e téntao de novo."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Queres gardar <xliff:g id="TYPE">%1$s</xliff:g> en: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Queres gardar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> en: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Queres gardar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g> en: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Queres actualizar <b><xliff:g id="LABEL">%1$s</xliff:g></b> con estes datos?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Queres actualizar <b><xliff:g id="LABEL">%2$s</xliff:g></b> con estes datos (<xliff:g id="TYPE">%1$s</xliff:g>)?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Queres actualizar <b><xliff:g id="LABEL">%3$s</xliff:g></b> con estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g>)?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Queres actualizar <b><xliff:g id="LABEL">%4$s</xliff:g></b> con estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>)?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Gardar"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Non, grazas"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Actualizar"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"contrasinal"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"enderezo"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"tarxeta de crédito"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 1cf889290d81..5e6c34d0f43a 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"બોડી સેન્સર્સ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"તમારા મહત્વપૂર્ણ ચિહ્નો વિશે સેન્સર ડેટા ઍક્સેસ કરો"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારી મહત્વપૂર્ણ સહી વિશેના સેન્સર ડેટાને ઍક્સેસ કરવાની મંજૂરી આપીએ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"સંગીત"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"તમારા સંગીતને ઍક્સેસ કરો"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ને તમારા સંગીતમાં ઍક્સેસ કરવાની મંજૂરી આપવી છે?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ફોટો અને વિડિઓ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"તમારા ફોટો & વિડિઓ ઍક્સેસ કરો"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"એપ્લિકેશનને ઉપયોગ માટે ફિંગરપ્રિન્ટ નમૂના ઉમેરવા અને કાઢી નાખવા માટે પદ્ધતિઓની વિનંતી કરવાની મંજૂરી આપે છે."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરો"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"એપ્લિકેશનને પ્રમાણીકરણ માટે ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"આપનો સંગીત સંગ્રહ વાંચવો"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"એપને તમારો સંગીત સંગ્રહ વાંચવાની મંજૂરી આપે છે."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"આપનો સંગીત સંગ્રહ સંશોધિત કરવો"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"એપને તમારો સંગીત સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"આપનો વીડિઓ સંગ્રહ વાંચવો"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"એપને તમારો વિડિઓ સંગ્રહ વાંચવાની મંજૂરી આપે છે."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"આપનો વિડિઓ સંગ્રહ સંશોધિત કરવો"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"એપને તમારો વિડિઓ સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"આપનો ફોટો સંગ્રહ વાંચવો"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"એપને તમારો ફોટો સંગ્રહ વાંચવાની મંજૂરી આપે છે."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"આપનો સંગીત સંગ્રહ સંશોધિત કરવો"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"આંશિક ફિંગરપ્રિન્ટ મળી. કૃપા કરીને ફરી પ્રયાસ કરો."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ફિંગરપ્રિન્ટ પ્રક્રિયા કરી શકાઈ નથી. કૃપા કરીને ફરી પ્રયાસ કરો."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ફિંગરપ્રિન્ટ સેન્સર ગંદું છે. કૃપા કરીને સાફ કરો અને ફરી પ્રયાસ કરો."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>ને <b><xliff:g id="LABEL">%2$s</xliff:g></b>માં સાચવીએ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> અને <xliff:g id="TYPE_1">%2$s</xliff:g>ને <b><xliff:g id="LABEL">%3$s</xliff:g></b>માં સાચવીએ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> અને <xliff:g id="TYPE_2">%3$s</xliff:g>ને <b><xliff:g id="LABEL">%4$s</xliff:g></b>માં સાચવીએ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> પર અપડેટ કરવું છે?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g>ને <b><xliff:g id="LABEL">%2$s</xliff:g></b> પર અપડેટ કરવું છે?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> અને <xliff:g id="TYPE_1">%2$s</xliff:g> ને <b><xliff:g id="LABEL">%3$s</xliff:g></b> પર અપડેટ કરવું છે?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> અને <xliff:g id="TYPE_2">%3$s</xliff:g>ને <b><xliff:g id="LABEL">%4$s</xliff:g></b>પર અપડેટ કરવું છે?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"સાચવો"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ના, આભાર"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"અપડેટ કરો"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"પાસવર્ડ"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"સરનામું"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ક્રેડિટ કાર્ડ"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index f9576e040508..f24a3c422ad4 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Biometrijski senzori"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupiti podacima senzora o vašim vitalnim znakovima"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa podacima senzora o vašim vitalnim znakovima?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Glazba"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"pristup glazbi"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa vašoj glazbi?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotografije i videozapisi"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"pristup fotografijama i & videozapisima"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Želite li dopustiti aplikaciji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> da pristupa vašim fotografijama i videozapisima?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Dohvaćati sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Pregledat će sadržaj prozora koji upotrebljavate."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključiti značajku Istraži dodirom"</string> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Aplikaciji omogućuje pozivanje načina za dodavanje i brisanje predložaka otisaka prstiju koji će se upotrijebiti."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"upotreba hardvera za čitanje otisaka prstiju"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Aplikaciji omogućuje upotrebu hardvera za čitanje otisaka prstiju radi autentifikacije."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"čitanje vaše glazbene zbirke"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Omogućuje aplikaciji čitanje vaše glazbene zbirke."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"izmjena vaše glazbene zbirke"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Omogućuje aplikaciji izmjenu vaše glazbene zbirke."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"čitanje vaše zbirke videozapisa"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Omogućuje aplikaciji čitanje vaše zbirke videozapisa."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"izmjena vaše zbirke videozapisa"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Omogućuje aplikaciji izmjenu vaše kolekcije videozapisa."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"čitanje vaše zbirke fotografija"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Omogućuje aplikaciji čitanje vaše zbirke fotografija."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"izmjena vaše zbirke fotografija"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Omogućuje aplikaciji izmjenu vaše zbirke fotografija."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz vaše medijske zbirke"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otiska prsta nije čist. Očistite ga i pokušajte ponovo."</string> @@ -1947,18 +1927,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Želite li da se podatak (<xliff:g id="TYPE">%1$s</xliff:g>) spremi na uslugu <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> spreme na uslugu <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Želite li da se <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> spreme na uslugu <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Želite li ažurirati na <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Želite li polje <xliff:g id="TYPE">%1$s</xliff:g> ažurirati na <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Želite li polja <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> ažurirati na <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Želite li polja <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> ažurirati na <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Spremi"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"zaporku"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresu"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditnu karticu"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index f957384aecc9..e7c1bf2c2aa0 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Testérzékelők"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"az érzékelők által mért, életjelekkel kapcsolatos adatok elérése"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen az életjelekkel kapcsolatos szenzoradatokhoz?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Zene"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"hozzáférés a zenékhez"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b&gt számára, hogy hozzáférjen az Ön zenéihez?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fényképek és videók"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"hozzáférés a fényképekhez és videókhoz"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b&gt számára, hogy hozzáférjen a fotókhoz és videókhoz?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Ablaktartalom lekérdezése"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"A használt ablak tartalmának vizsgálata."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Felfedezés érintéssel bekapcsolása"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Lehetővé teszi az alkalmazás számára a használni kívánt ujjlenyomatsablonok hozzáadására és törlésére szolgáló metódusok indítását."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ujjlenyomat-olvasó hardver használata"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Lehetővé teszi az alkalmazás számára az ujjlenyomat-olvasó hardver hitelesítésre való használatát"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"a zenei gyűjtemény olvasása"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Engedélyezi az alkalmazásnak a zenei gyűjtemény olvasását."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"a zenei gyűjtemény módosítása"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Engedélyezi az alkalmazásnak a zenei gyűjtemény módosítását."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"a videógyűjtemény olvasása"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Engedélyezi az alkalmazásnak a videógyűjtemény olvasását."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"a videógyűjtemény módosítása"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Engedélyezi az alkalmazásnak a videógyűjtemény módosítását."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"a fényképgyűjtemény olvasása"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Engedélyezi az alkalmazásnak a fényképgyűjtemény olvasását."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"a fényképgyűjtemény módosítása"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Engedélyezi az alkalmazásnak a fényképgyűjtemény módosítását."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"helyek olvasása a médiagyűjteményből"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"A rendszer az ujjlenyomatnak csak egy részletét érzékelte. Próbálkozzon újra."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Az ujjlenyomat-olvasó koszos. Tisztítsa meg, majd próbálkozzon újra."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Menti a következőt: <xliff:g id="TYPE">%1$s</xliff:g> ide: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Menti a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g> és <xliff:g id="TYPE_1">%2$s</xliff:g> ide: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Menti a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> és <xliff:g id="TYPE_2">%3$s</xliff:g> ide: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Frissít a következőre: <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Frissíti a következőt: <xliff:g id="TYPE">%1$s</xliff:g> erre: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Frissíti a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g> és <xliff:g id="TYPE_1">%2$s</xliff:g> erre: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Frissíti a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> és <xliff:g id="TYPE_2">%3$s</xliff:g> erre: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Mentés"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nem, köszönöm"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Frissítés"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"jelszó"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"cím"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"hitelkártya"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 978e66198bdf..a46d5e6f3252 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Մարմնի սենսորներ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Թույլ տա՞լ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> հավելվածին սենսորից ստանալ ձեր կենսագործունեության հիմնական տվյալները:"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Երաժշտություն"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"երաժշտության հասանելիություն"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Հասանելի դարձնե՞լ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> հավելվածին ձեր երաժշտությունը:"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Լուսանկարներ և տեսանյութեր"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"լուսանկարների և տեսանյութերի հասանելիություն"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Հավելվածին թույլ է տալիս կատարել այնպիսի գործառույթներ, որոնց միջոցով կարելի է օգտագործման համար ավելացնել և հեռացնել մատնահետքերի նմուշներ:"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"օգտագործել մատնահետքերի գրանցման սարքը"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Հավելվածին թույլ է տալիս նույնականացման համար օգտագործել մատնահետքերի գրանցման սարքը"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ճանաչել երաժշտական հավաքածուն"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Թույլ է տալիս հավելվածին ճանաչել ձեր երաժշտական հավաքածուն:"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"փոփոխել երաժշտական հավաքածուն"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Թույլ է տալիս հավելվածին փոփոխել ձեր երաժշտական հավաքածուն:"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ճանաչել տեսանյութերի հավաքածուն"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Թույլ է տալիս հավելվածին ճանաչել ձեր տեսանյութերի հավաքածուն:"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"փոփոխել տեսանյութերի հավաքածուն"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Թույլ է տալիս հավելվածին փոփոխել ձեր տեսանյութերի հավաքածուն:"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ճանաչել լուսանկարների հավաքածուն"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Թույլ է տալիս հավելվածին ճանաչել ձեր լուսանկարների հավաքածուն:"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"փոփոխել լուսանկարների հավաքածուն"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Մատնահետքը հայտնաբերվել է մասամբ: Փորձեք նորից:"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Պահե՞լ <xliff:g id="TYPE">%1$s</xliff:g>ը <b><xliff:g id="LABEL">%2$s</xliff:g></b> ծառայությունում"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ն ու <xliff:g id="TYPE_1">%2$s</xliff:g>ը <b><xliff:g id="LABEL">%3$s</xliff:g></b> ծառայությունում"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Պահե՞լ <xliff:g id="TYPE_0">%1$s</xliff:g>ը, <xliff:g id="TYPE_1">%2$s</xliff:g>ն ու <xliff:g id="TYPE_2">%3$s</xliff:g>ը <b><xliff:g id="LABEL">%4$s</xliff:g></b> ծառայությունում"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Թարմացնե՞լ <b><xliff:g id="LABEL">%1$s</xliff:g></b> ծառայության տվյալները"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Թարմացնե՞լ <b><xliff:g id="LABEL">%2$s</xliff:g></b> ծառայության տվյալները (<xliff:g id="TYPE">%1$s</xliff:g>)"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Թարմացնե՞լ <b><xliff:g id="LABEL">%3$s</xliff:g></b> ծառայության տվյալները (<xliff:g id="TYPE_0">%1$s</xliff:g> և <xliff:g id="TYPE_1">%2$s</xliff:g>)"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Թարմացնե՞լ <b><xliff:g id="LABEL">%4$s</xliff:g></b> ծառայության տվյալները (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> և <xliff:g id="TYPE_2">%3$s</xliff:g>)"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Պահել"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ոչ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Թարմացնել"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"գաղտնաբառ"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"հասցե"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"վարկային քարտ"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 7ba8e2c3c122..ed5444d9ed3e 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensor Tubuh"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"mengakses data sensor tentang tanda-tanda vital"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses data sensor tentang tanda-tanda vital Anda?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"mengakses musik Anda"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> untuk mengakses musik?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Foto & Video"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"mengakses foto & video Anda"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Izinkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> untuk mengakses foto & video?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Mengambil konten jendela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Memeriksa konten jendela tempat Anda berinteraksi."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Mengaktifkan Jelajahi dengan Sentuhan"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Mengizinkan aplikasi memanggil metode untuk menambahkan dan menghapus template sidik jari untuk digunakan."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan hardware sidik jari"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Mengizinkan aplikasi untuk menggunakan hardware sidik jari untuk otentikasi"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"membaca koleksi musik Anda"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Mengizinkan aplikasi untuk membaca koleksi musik Anda."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"memodifikasi koleksi musik Anda"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Mengizinkan aplikasi untuk memodifikasi koleksi musik Anda."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"membaca koleksi video Anda"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Mengizinkan aplikasi untuk membaca koleksi video Anda."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"memodifikasi koleksi video Anda"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Mengizinkan aplikasi untuk memodifikasi koleksi video Anda."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"membaca koleksi foto Anda"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Mengizinkan aplikasi untuk membaca koleksi foto Anda."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"memodifikasi koleksi foto Anda"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Mengizinkan aplikasi untuk memodifikasi koleksi foto Anda."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"membaca lokasi dari koleksi media Anda"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sebagian sidik jari terdeteksi. Coba lagi."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses sidik jari. Coba lagi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Simpan <xliff:g id="TYPE">%1$s</xliff:g> ke <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Simpan <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> ke <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Simpan <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, dan <xliff:g id="TYPE_2">%3$s</xliff:g> ke <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Update ke <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Update <xliff:g id="TYPE">%1$s</xliff:g> ke <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Update <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> ke <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Update <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, dan <xliff:g id="TYPE_2">%3$s</xliff:g> ke <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Simpan"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Lain kali"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"sandi"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"alamat"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kartu kredit"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index a2c79c043984..330b0106d3e1 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Líkamsskynjarar"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"aðgangur að skynjaragögnum yfir lífsmörk þín"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Viltu veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að skynjaragögnum yfir lífsmörk þín?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Tónlist"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"fá aðgang að tónlistinni þinni"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Viltu veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að tónlistinni þinni?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Myndir og myndskeið"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"fá aðgang að myndunum og myndskeiðunum þínum"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Viltu veita <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aðgang að myndunum og myndskeiðunum þínum?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Sækja innihald glugga"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Kanna innihald glugga sem þú ert að nota."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Kveikja á snertikönnun"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Gerir forritinu kleift að beita aðferðum til að bæta við og eyða fingrafarasniðmátum til notkunar."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"nota fingrafarabúnað"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Leyfir forritinu að nota fingrafarabúnað til auðkenningar"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"lesa tónlistarsafnið þitt"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Leyfir forritinu að lesa tónlistarsafnið þitt."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"breyta tónlistarsafninu þínu"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Leyfir forritinu að breyta tónlistarsafninu þínu."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"lesa myndskeiðasafnið þitt"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Leyfir forritinu að lesa myndskeiðasafnið þitt."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"breyta myndskeiðasafninu þínu"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Leyfir forritinu að breyta myndskeiðasafninu þínu."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"lesa myndasafnið þitt"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Leyfir forritinu að lesa myndasafnið þitt."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"breyta myndasafninu þínu"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Leyfir forritinu að breyta myndasafninu þínu."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"lesa staðsetningar úr efnissafninu þínu"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hluti fingrafars greindist. Reyndu aftur."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingrafaraskynjarinn er óhreinn. Hreinsaðu hann og reyndu aftur."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vista <xliff:g id="TYPE">%1$s</xliff:g> á <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vista <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> á <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vista <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> á <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Viltu uppfæra í <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Viltu uppfæra <xliff:g id="TYPE">%1$s</xliff:g> í <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Viltu uppfæra <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> í <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Viltu uppfæra <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> í <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Vista"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nei, takk"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Uppfæra"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"aðgangsorð"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"heimilisfang"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkort"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 60eb471b3a36..9a3fe87bebbd 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"חיישני גוף"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"גישה אל נתוני חיישנים של הסימנים החיוניים שלך"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה לנתוני חיישנים העוקבים אחר הסימנים החיוניים שלך?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"מוזיקה"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"גישה למוזיקה שלך"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"האם לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה למוזיקה שלך?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"תמונות וסרטונים"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"גישה לתמונות ולסרטונים שלך"</string> + <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> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"מאפשר לאפליקציה להפעיל שיטות להוספה ומחיקה של תבניות טביעות אצבעות שבהן ייעשה שימוש."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"חומרה של טביעות אצבעות"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"מאפשר לאפליקציה להשתמש בחומרה של טביעות אצבעות לצורך אימות"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"לקרוא את אוסף המוזיקה שלך"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"מאפשרת לאפליקציה לקרוא את אוסף המוזיקה שלך."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"לשנות את אוסף המוזיקה שלך"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"מאפשרת לאפליקציה לשנות את אוסף המוזיקה שלך."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"לקרוא את אוסף הסרטונים שלך"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"מאפשרת לאפליקציה לקרוא את אוסף הסרטונים שלך."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"לשנות את אוסף הסרטונים שלך"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"מאפשרת לאפליקציה לשנות את אוסף הסרטונים שלך."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"לקרוא את אוסף התמונות שלך"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"מאפשרת לאפליקציה לקרוא את אוסף התמונות שלך."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"לשנות את אוסף התמונות שלך"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"מאפשרת לאפליקציה לשנות את אוסף התמונות שלך."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"לקרוא מיקומים מאוסף המדיה שלך"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"זוהתה טביעת אצבע חלקית. נסה שוב."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"לא ניתן היה לעבד את טביעת האצבע. נסה שוב."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"החיישן של טביעות האצבעות מלוכלך. נקה אותו ונסה שוב."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"האם לשמור <xliff:g id="TYPE">%1$s</xliff:g> בשירות <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"האם לשמור <xliff:g id="TYPE_0">%1$s</xliff:g> ו<xliff:g id="TYPE_1">%2$s</xliff:g> בשירות <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"האם לשמור <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ו<xliff:g id="TYPE_2">%3$s</xliff:g> בשירות <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"האם לעדכן בשירות <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"האם לעדכן את <xliff:g id="TYPE">%1$s</xliff:g> בשירות <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"האם לעדכן את <xliff:g id="TYPE_0">%1$s</xliff:g> ואת <xliff:g id="TYPE_1">%2$s</xliff:g> בשירות <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"האם לעדכן את <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ו<xliff:g id="TYPE_2">%3$s</xliff:g> בשירות <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"שמירה"</string> <string name="autofill_save_no" msgid="2625132258725581787">"לא, תודה"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"עדכון"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"סיסמה"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"כתובת"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"כרטיס אשראי"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index e72876279d25..0a383dff04f8 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"სხეულის სენსორები"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომა"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"გსურთ, მიანიჭოთ <b><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</b> თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომის ნებართვა?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"მუსიკა"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"თქვენს მუსიკაზე წვდომა"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"გსურთ, მიანიჭოთ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>-ს თქვენს მუსიკაზე წვდომა?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ფოტოები და ვიდეოები"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"თქვენს ფოტოებსა და ვიდეოებზე წვდომა"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"საშუალებას აძლევს აპლიკაციას დაამატოს ან ამოშალოს გამოსაყენებელი თითის ანაბეჭდის ნიმუშები,"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"თითის ანაბეჭდის აპარატის გამოყენება"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"საშუალებას აძლევს აპლიკაციას გამოიყენოს ავტენთიფიკაციისათვის თითის ანაბეჭდის აპარატი"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"თქვენი მუსიკალური კოლექციის გაცნობა"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"აპი შეძლებს თქვენი მუსიკალური კოლექციის გაცნობას."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"თქვენი მუსიკალური კოლექციის შეცვლა"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"აპი შეძლებს თქვენი მუსიკალური კოლექციის შეცვლას."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"თქვენი ვიდეოკოლექციის გაცნობა"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"აპი შეძლებს თქვენი ვიდეოკოლექციის გაცნობას."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"თქვენი ვიდეოკოლექციის შეცვლა"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"აპი შეძლებს თქვენი ვიდეოკოლექციის შეცვლას."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"თქვენი ფოტოკოლექციის გაცნობა"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"აპი შეძლებს თქვენი ფოტოკოლექციის გაცნობას."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"თქვენი ფოტოკოლექციის შეცვლა"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"აპი შეძლებს თქვენი ფოტოკოლექციის შეცვლას."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"მდებარეობების გაცნობა თქვენი მედიაკოლექციიდან"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"აღმოჩენილია თითის ნაწილობრივი ანაბეჭდი. გთხოვთ, სცადოთ ხელახლა."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"თითის ანაბეჭდი ვერ მუშავდება. გთხოვთ, სცადოთ ხელახლა."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"თითის ანაბეჭდის სენსორი დაბინძურებულია. გთხოვთ, გაასუფთაოთ და სცადოთ ხელახლა."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"გსურთ, შეინახოთ <xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g>-ში</b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"გსურთ, შეინახოთ <xliff:g id="TYPE_0">%1$s</xliff:g> და <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g>-ში</b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"გსურთ, შეინახოთ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, და <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g>-ში</b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"გსურთ, განაახლოთ <b><xliff:g id="LABEL">%1$s</xliff:g></b>-ზე?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"გსურთ, განაახლოთ <xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b>-ზე?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"გსურთ, განაახლოთ <xliff:g id="TYPE_0">%1$s</xliff:g> და <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b>-ზე?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"გსურთ, განაახლოთ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> და <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b>-ზე?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"შენახვა"</string> <string name="autofill_save_no" msgid="2625132258725581787">"არა, გმადლობთ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"განახლება"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"პაროლი"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"მისამართი"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"საკრედიტო ბარათი"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 2e3ba648b341..25099585fb9d 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Дене датчиктері"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ағза күйінің көрсеткіштері туралы сенсор деректеріне қатынасу"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> қолданбасына негізгі физиологиялық көрсеткіштерді көрсететін сенсорлық деректерді пайдалануға рұқсат берілсін бе?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"музыка мазмұнына кіру"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> қолданбасына музыка мазмұнына кіруге рұқсат етілсін бе?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Суреттер және бейнелер"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"суреттер мен бейнелерге кіру"</string> + <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">"Explore by Touch функциясын қосу"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Қолданбаға пайдаланатын саусақ ізі үлгілерін қосу және жою әдістерін шақыруға мүмкіндік береді."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"саусақ ізі жабдығын пайдалану"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Қолданбаға аутентификацияалу үшін саусақ ізі жабдығын пайдалануға мүмкіндік береді"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"музыка жинағын оқу"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Қолданбаға музыка жинағын оқуға мүмкіндік береді."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"музыка жинағын өзгерту"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Қолданбаға музыка жинағын өзгертуге мүмкіндік береді."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"бейнелер жинағын оқу"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Қолданбаға бейнелер жинағын оқуға мүмкіндік береді."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"бейнелер жинағын өзгерту"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Қолданбаға бейнелер жинағын өзгертуге мүмкіндік береді."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"суреттер жинағын оқу"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Қолданбаға суреттер жинағын оқуға мүмкіндік береді."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"суреттер жинағын өзгерту"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Қолданбаға суреттер жинағын өзгертуге мүмкіндік береді."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"медиамазмұн жинағынан геодеректерді оқу"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Саусақ ізі ішінара анықталды. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Саусақ ізі сенсоры лас. Тазалап, әрекетті қайталаңыз."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> \"<xliff:g id="LABEL">%2$s</xliff:g>\" қызметінде сақталсын ба?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> және <xliff:g id="TYPE_1">%2$s</xliff:g> \"<xliff:g id="LABEL">%3$s</xliff:g>\" қызметінде сақталсын ба?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> және <xliff:g id="TYPE_2">%3$s</xliff:g> \"<xliff:g id="LABEL">%4$s</xliff:g>\" қызметінде сақталсын ба?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> қызметінде жаңартылсын ба?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> мәліметі <b><xliff:g id="LABEL">%2$s</xliff:g></b> қызметінде жаңартылсын ба?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> және <xliff:g id="TYPE_1">%2$s</xliff:g> мәліметі <b><xliff:g id="LABEL">%3$s</xliff:g></b> қызметінде жаңартылсын ба?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> және <xliff:g id="TYPE_2">%3$s</xliff:g> мәліметі <b><xliff:g id="LABEL">%4$s</xliff:g></b> қызметінде жаңартылсын ба?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Сақтау"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Жоқ, рақмет"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Жаңарту"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"құпия сөз"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"мекенжай"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"несие картасы"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 6e2d41b6e904..e24c9a09d918 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ឧបករណ៍ចាប់សញ្ញារាងកាយ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ចូលដំណើរការទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នក"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"អនុញ្ញាតឱ្យ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នក?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"តន្ត្រី"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ចូលប្រើតន្ត្រីរបស់អ្នក"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"អនុញ្ញាតឱ្យ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ចូលប្រើតន្រ្តីរបស់អ្នក?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"រូបថត និងវីដេអូ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ចូលប្រើរូបថត និងវីដេអូរបស់អ្នក"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"អនុញ្ញាតឲ្យកម្មវិធីប្រើវិធីសាស្ត្របន្ថែម និងលុបពុម្ពម្រាមដៃសម្រាប់ប្រើប្រាស់។"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ប្រើផ្នែករឹងស្នាមម្រាមដៃ"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"អនុញ្ញាតឲ្យកម្មវិធីប្រើផ្នែករឹងស្នាមម្រាមដៃសម្រាប់ការផ្ទៀងផ្ទាត់"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"អានបណ្ដុំតន្ត្រីរបស់អ្នក"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"អនុញ្ញាតឱ្យកម្មវិធីអានបណ្ដុំតន្រ្តីរបស់អ្នក។"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"កែប្រែបណ្ដុំតន្ត្រីរបស់អ្នក"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំតន្រ្តីរបស់អ្នក។"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"អានបណ្ដុំវីដេអូរបស់អ្នក"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"អនុញ្ញាតឱ្យកម្មវិធីអានបណ្ដុំវីដេអូរបស់អ្នក។"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"កែប្រែបណ្ដុំវីដេអូរបស់អ្នក"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំវីដេអូរបស់អ្នក។"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"អានបណ្ដុំរូបថតរបស់អ្នក"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"អនុញ្ញាតឱ្យកម្មវិធីអានបណ្ដុំរូបថតរបស់អ្នក។"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"កែប្រែបណ្ដុំរូបថតរបស់អ្នក"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំរូបថតរបស់អ្នក។"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"អានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"អនុញ្ញាតឱ្យកម្មវិធីអានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក។"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"បានផ្តិតយកស្នាមម្រាមដៃមិនពេញលក្ខណៈ។ សូមព្យាយាមម្តងទៀត។"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"មិនអាចដំណើរការស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្តងទៀត។"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ឧបករណ៍ផ្តិតម្រាមដៃប្រលាក់ហើយ។ សូមសម្អាត ហើយព្យាយាមម្តងទៀត។"</string> @@ -1914,18 +1894,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"រក្សាទុក <xliff:g id="TYPE">%1$s</xliff:g> ទៅក្នុង <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"រក្សាទុក <xliff:g id="TYPE_0">%1$s</xliff:g> និង <xliff:g id="TYPE_1">%2$s</xliff:g> ទៅក្នុង <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"រក្សាទុក <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, និង <xliff:g id="TYPE_2">%3$s</xliff:g> ទៅក្នុង <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"ធ្វើបច្ចុប្បន្នភាពទៅ <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"ធ្វើបច្ចុប្បន្នភាព <xliff:g id="TYPE">%1$s</xliff:g> ទៅ <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"ធ្វើបច្ចុប្បន្នភាព <xliff:g id="TYPE_0">%1$s</xliff:g> និង <xliff:g id="TYPE_1">%2$s</xliff:g> ទៅ <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"ធ្វើបច្ចុប្បន្នភាព <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> និង <xliff:g id="TYPE_2">%3$s</xliff:g> ទៅ <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"រក្សាទុក"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ទេ អរគុណ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"ធ្វើបច្ចុប្បន្នភាព"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"ពាក្យសម្ងាត់"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"អាសយដ្ឋាន"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"បណ្ណឥណទាន"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index e99d53a53d99..158a316d7798 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ದೇಹ ಸೆನ್ಸರ್ಗಳು"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸಾರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಿ"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"ಸಂಗೀತ"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ನಿಮ್ಮ ಸಂಗೀತವನ್ನು ಪ್ರವೇಶಿಸಿ"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"ನಿಮ್ಮ ಸಂಗೀತವನ್ನು ಪ್ರವೇಶಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ಫೋಟೋಗಳು & ವೀಡಿಯೊಗಳು"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ನಿಮ್ಮ ಫೋಟೋಗಳು & ವೀಡಿಯೊಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ಬಳಕೆಗೆ ಬೆರಳಚ್ಚು ಟೆಂಪ್ಲೇಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಮತ್ತು ಅಳಿಸಲು ವಿಧಾನಗಳನ್ನು ಮನವಿ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ಬೆರಳಚ್ಚು ಹಾರ್ಡ್ವೇರ್ ಬಳಸಿ"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಬೆರಳಚ್ಚು ಹಾರ್ಡ್ವೇರ್ ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ನಿಮ್ಮ ಸಂಗೀತ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಿ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ನಿಮ್ಮ ಸಂಗೀತ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ನಿಮ್ಮ ಸಂಗೀತ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ನಿಮ್ಮ ಸಂಗೀತ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ನಿಮ್ಮ ವೀಡಿಯೊ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಿ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ನಿಮ್ಮ ವೀಡಿಯೊ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ನಿಮ್ಮ ವೀಡಿಯೊ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ನಿಮ್ಮ ವೀಡಿಯೊ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಿ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಿ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ಭಾಗಶಃ ಬೆರಳಚ್ಚು ಪತ್ತೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ಬೆರಳಚ್ಚು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ಬೆರಳಚ್ಚು ಸೆನ್ಸಾರ್ ಕೊಳೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%2$s</xliff:g></b>ನಲ್ಲಿ ಉಳಿಸುವುದೇ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> ಹಾಗೂ <xliff:g id="TYPE_1">%2$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%3$s</xliff:g></b>ನಲ್ಲಿ ಉಳಿಸುವುದೇ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ಹಾಗೂ <xliff:g id="TYPE_2">%3$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%4$s</xliff:g></b>ನಲ್ಲಿ ಉಳಿಸುವುದೇ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>ಗೆ ಅಪ್ಡೇಟ್ ಮಾಡುವುದೇ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%2$s</xliff:g></b>ಗೆ ಅಪ್ಡೇಟ್ ಮಾಡುವುದೇ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> ಹಾಗೂ <xliff:g id="TYPE_1">%2$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%3$s</xliff:g></b>ಗೆ ಅಪ್ಡೇಟ್ ಮಾಡುವುದೇ?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ಹಾಗೂ <xliff:g id="TYPE_2">%3$s</xliff:g> ಅನ್ನು <b><xliff:g id="LABEL">%4$s</xliff:g></b>ಗೆ ಅಪ್ಡೇಟ್ ಮಾಡುವುದೇ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"ಉಳಿಸಿ"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ಬೇಡ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"ಅಪ್ಡೇಟ್"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"ಪಾಸ್ವರ್ಡ್"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ವಿಳಾಸ"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 89e726992a49..776f773480d4 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"인체 감지 센서"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 액세스"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>에서 생체 신호에 관한 센서 데이터에 액세스하도록 허용하시겠습니까?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"음악"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"음악에 액세스"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>에서 내 음악에 액세스하도록 허용하시겠습니까?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"사진 및 동영상"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"사진 및 동영상에 액세스"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"음악 컬렉션 읽기"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"앱에서 음악 컬렉션을 읽도록 허용합니다."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"음악 컬렉션 수정"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"앱에서 음악 컬렉션을 수정하도록 허용합니다."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"동영상 컬렉션 읽기"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"앱에서 동영상 컬렉션을 읽도록 허용합니다."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"동영상 컬렉션 수정"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"앱에서 동영상 컬렉션을 수정하도록 허용합니다."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"사진 컬렉션 읽기"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"앱에서 사진 컬렉션을 읽도록 허용합니다."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"사진 컬렉션 수정"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"앱에서 사진 컬렉션을 수정하도록 허용합니다."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"미디어 컬렉션에서 위치 읽기"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>을(를) <b><xliff:g id="LABEL">%2$s</xliff:g></b>에 저장하시겠습니까?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> 및 <xliff:g id="TYPE_1">%2$s</xliff:g>을(를) <b><xliff:g id="LABEL">%3$s</xliff:g></b>에 저장하시겠습니까?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g>을(를) <b><xliff:g id="LABEL">%4$s</xliff:g></b>에 저장하시겠습니까?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>(으)로 업데이트하시겠습니까?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g>을(를) <b><xliff:g id="LABEL">%2$s</xliff:g></b>(으)로 업데이트하시겠습니까?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> 및 <xliff:g id="TYPE_1">%2$s</xliff:g>을(를) <b><xliff:g id="LABEL">%3$s</xliff:g></b>(으)로 업데이트하시겠습니까?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g>을(를) <b><xliff:g id="LABEL">%4$s</xliff:g></b>(으)로 업데이트하시겠습니까?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"저장"</string> <string name="autofill_save_no" msgid="2625132258725581787">"사용 안함"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"업데이트"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"비밀번호"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"주소"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"신용카드"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 55a721ee36fb..1c1e9a940a30 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Дене сенсорлору"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"организмдин абалына көз салган сенсордун дайындарына мүмкүнчүлүк алуу"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> колдонмосуна организмдин абалына көз салган сенсордун дайындарын пайдаланууга уруксат берилсинби?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"музыкага кирүү мүмкүнчүлүгү"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> колдонмосуна музыканы пайдаланууга уруксат берилсинби?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Сүрөттөр жана видеолор"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"сүрөттөр менен видеолорго кирүү мүмкүнчүлүгү"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Колдонмого пайдалануу үчүн манжа изинин үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"манжа изинин аппараттык камсыздоосун колдонуу"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Колдонмого аныктыгын текшерүү үчүн манжа изинин аппараттык камсыздоосун пайдалануу мүмкүндүгүн берет"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"музыка жыйнагыңызды окуу"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Колдонмого музыка жыйнагыңызды окууга мүмкүнчүлүк берет."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"музыка жыйнагыңызды өчүрүү"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Колдонмого музыка жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"видео жыйнагыңызды окуу"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Колдонмого видео жыйнагыңызды окууга мүмкүнчүлүк берет."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"видео жыйнагыңызды өзгөртүү"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Колдонмого видео жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"сүрөт жыйнагыңызды окуу"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Колдонмого сүрөт жыйнагыңызды окууга мүмкүнчүлүк берет."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"сүрөт жыйнагыңызды өзгөртүү"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"медиа жыйнагыңыз сакталган жерлерди окуу"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Манжа изи жарым-жартылай аныкталды. Кайра аракет кылыңыз."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Манжа изи иштелбей койду. Кайра аракет кылыңыз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Манжа изинин сенсору кирдеп калган. Тазалап, кайра аракет кылыңыз."</string> @@ -1914,18 +1894,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> кызматында сакталсынбы?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> жана <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> кызматында сакталсынбы?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> жана <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> кызматында сакталсынбы?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> кызматына жаңыртылсынбы?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> кызматына жаңыртылсынбы?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> жана <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> кызматына жаңыртылсынбы?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> жана <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> кызматына жаңыртылсынбы?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Сактоо"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Жок, рахмат"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Жаңыртуу"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"сырсөз"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"дарек"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"насыя картасы"</string> diff --git a/core/res/res/values-land/dimens_package_installer.xml b/core/res/res/values-land/dimens_permission_controller.xml index 2146241fd830..2146241fd830 100644 --- a/core/res/res/values-land/dimens_package_installer.xml +++ b/core/res/res/values-land/dimens_permission_controller.xml diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 24cef031887b..b17b5ab76958 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ເຊັນເຊີຮ່າງກາຍ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ເຂົ້າຫາຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານ"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານບໍ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"ເພງ"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ເຂົ້າເຖິງເພງຂອງທ່ານ"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"ອະນຸຍາດ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ໃຫ້ເຂົ້າເຖິງເພງຂອງທ່ານບໍ?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ຮູບພາບ ແລະ ວິດີໂອ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ເຂົ້າເຖິງຮູບພາບ ແລະ ວິດີໂອຂອງທ່ານ"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ອະນຸຍາດໃຫ້ແອັບເຮັດໃຫ້ວິທີການຕ່າງໆເພີ່ມ ແລະລຶບແມ່ແບບລາຍນີ້ວມືສຳລັບການໃຊ້."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ໃຊ້ຮາດແວລາຍນີ້ວມື"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ອະນຸຍາດໃຫ້ແອັບນຳໃຊ້ຮາດແວລາຍນີ້ວມືສຳລັບການຮັບຮອງ"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ອ່ານຄໍເລັກຊັນເພງຂອງທ່ານ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ອະນຸຍາດໃຫ້ແອັບອ່ານຄໍເລັກຊັນເພງຂອງທ່ານ."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ແກ້ໄຂຄໍເລັກຊັນເພງຂອງທ່ານ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນເພງຂອງທ່ານ."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ອ່ານຄໍເລັກຊັນວິດີໂອຂອງທ່ານ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ອະນຸຍາດໃຫ້ແອັບອ່ານຄໍເລັກຊັນວິດີໂອຂອງທ່ານ."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ແກ້ໄຂຄໍເລັກຊັນວິດີໂອຂອງທ່ານ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນວິດີໂອຂອງທ່ານ."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ອ່ານຄໍເລັກຊັນຮູບຂອງທ່ານ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ອະນຸຍາດໃຫ້ແອັບອ່ານຄໍເລັກຊັນຮູບຂອງທ່ານ."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ກວດພົບລາຍນີ້ວມືບາງສ່ວນແລ້ວ. ກະລຸນາລອງໃໝ່ອີກ."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ບໍ່ສາມາດດຳເນີນການລາຍນີ້ວມືໄດ້. ກະລຸນາລອງໃໝ່ອີກ."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ເຊັນເຊີລາຍນີ້ວມືເປື້ອນ. ກະລຸນາທຳຄວາມສະອາດ ແລະລອງໃໝ່ອີກ."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"ບັນທຶກ <xliff:g id="TYPE">%1$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%2$s</xliff:g></b> ບໍ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"ບັນທຶກ <xliff:g id="TYPE_0">%1$s</xliff:g> ແລະ <xliff:g id="TYPE_1">%2$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%3$s</xliff:g></b> ບໍ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"ບັນທຶກ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ແລະ <xliff:g id="TYPE_2">%3$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%4$s</xliff:g></b> ບໍ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"ອັບເດດ <b><xliff:g id="LABEL">%1$s</xliff:g></b> ບໍ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"ອັບເດດ <xliff:g id="TYPE">%1$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%2$s</xliff:g></b> ບໍ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"ອັບເດດ <xliff:g id="TYPE_0">%1$s</xliff:g> ແລະ <xliff:g id="TYPE_1">%2$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%3$s</xliff:g></b> ບໍ?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"ອັບເດດ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ແລະ <xliff:g id="TYPE_2">%3$s</xliff:g> ໃສ່ <b><xliff:g id="LABEL">%4$s</xliff:g></b> ບໍ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"ບັນທຶກ"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ບໍ່, ຂອບໃຈ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"ອັບເດດ"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"ລະຫັດຜ່ານ"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ທີ່ຢູ່"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ບັດເຄຣດິດ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index c61c30ff682b..9409c7deafb6 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Kūno jutikliai"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pasiekti jutiklių duomenis apie gyvybinius ženklus"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Suteikti <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> galimybę pasiekti jutiklių duomenis apie gyvybinius ženklus?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"pasiekti muziką"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Suteikti programai <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prieigą prie muzikos?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Nuotraukos ir vaizdo įrašai"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"pasiekti nuotraukas ir vaizdo įrašus"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Suteikti programai <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prieigą prie nuotraukų ir vaizdo įrašų?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Gauti lango turinį"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Tikrinti lango, su kuriuo sąveikaujate, turinį."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Įjungti „Naršyti paliečiant“"</string> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Leidžiama programai aktyvinti metodus, norint pridėti ir ištrinti naudojamus kontrolinių kodų šablonus."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"naudoti kontrolinio kodo aparatinę įrangą"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Leidžiama programai naudoti kontrolinio kodo aparatinę įrangą tapatybei nustatyti"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"skaityti muzikos kolekciją"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Programai leidžiama skaityti muzikos kolekciją."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"keisti muzikos kolekciją"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Programai leidžiama keisti muzikos kolekciją."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"skaityti vaizdo įrašų kolekciją"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Programai leidžiama skaityti vaizdo įrašų kolekciją."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"keisti vaizdo įrašų kolekciją"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Programai leidžiama keisti vaizdo įrašų kolekciją."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"skaityti nuotraukų kolekciją"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Programai leidžiama skaityti nuotraukų kolekciją."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"keisti nuotraukų kolekciją"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Programai leidžiama keisti nuotraukų kolekciją."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"skaityti vietoves iš medijos kolekcijos"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Aptiktas dalinis kontrolinis kodas. Bandykite dar kartą."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nepavyko apdoroti kontrolinio kodo. Bandykite dar kartą."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kontrolinio kodo jutiklis purvinas. Nuvalykite ir bandykite dar kartą."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Išsaugoti <xliff:g id="TYPE">%1$s</xliff:g> sistemoje <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Išsaugoti <xliff:g id="TYPE_0">%1$s</xliff:g> ir <xliff:g id="TYPE_1">%2$s</xliff:g> sistemoje <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Išsaugoti <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ir <xliff:g id="TYPE_2">%3$s</xliff:g> sistemoje <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Atnaujinti paslaugoje <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Atnaujinti <xliff:g id="TYPE">%1$s</xliff:g> paslaugoje <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Atnaujinti <xliff:g id="TYPE_0">%1$s</xliff:g> ir <xliff:g id="TYPE_1">%2$s</xliff:g> paslaugoje <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Atnaujinti <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ir <xliff:g id="TYPE_2">%3$s</xliff:g> paslaugoje <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Išsaugoti"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Ne, ačiū"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Atnaujinti"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"slaptažodį"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresą"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredito kortelę"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index ea7140b7ce25..272deb36949b 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Ķermeņa sensori"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"piekļūt sensoru datiem par jūsu veselības rādījumiem"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vai atļaut lietotnei <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt sensoru uztvertajiem veselības rādījumiem?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Mūzika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"Piekļūt jūsu mūzikai"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vai atļaut lietotnei <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt jūsu mūzikai?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotoattēli un videoklipi"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"Piekļūt jūsu fotoattēliem un videoklipiem"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vai atļaut lietotnei <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> piekļūt jūsu fotoattēliem videoklipiem?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Izgūt loga saturu."</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Skatīt tā loga saturu, ar kuru mijiedarbojaties."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktivizēt funkciju “Pārlūkot pieskaroties”."</string> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Atļauj lietotnei izsaukt metodes izmantojamo pirkstu nospiedumu veidņu pievienošanai un dzēšanai."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"lietot pirkstu nospiedumu aparatūru"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Atļauj lietotnei izmantot pirkstu nospiedumu aparatūru autentificēšanai."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"Lasīt jūsu mūzikas kolekciju"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Ļauj lietotnei lasīt jūsu mūzikas kolekciju."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"Pārveidot jūsu mūzikas kolekciju"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Ļauj lietotnei pārveidot jūsu mūzikas kolekciju."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"Lasīt jūsu videoklipu kolekciju"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Ļauj lietotnei lasīt jūsu videoklipu kolekciju."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"Pārveidot jūsu videoklipu kolekciju"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Ļauj lietotnei pārveidot jūsu videoklipu kolekciju."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"Lasīt jūsu fotoattēlu kolekciju"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Ļauj lietotnei lasīt jūsu fotoattēlu kolekciju."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"Pārveidot jūsu fotoattēlu kolekciju"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ļauj lietotnei pārveidot jūsu fotoattēlu kolekciju."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"Lasīt atrašanās vietas no jūsu multivides kolekcijas"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Noteikts daļējs pirksta nospiedums. Lūdzu, mēģiniet vēlreiz."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Pirkstu nospiedumu sensors ir netīrs. Lūdzu, notīriet to un mēģiniet vēlreiz."</string> @@ -1947,18 +1927,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vai saglabāt vienumu “<xliff:g id="TYPE">%1$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vai saglabāt vienumus “<xliff:g id="TYPE_0">%1$s</xliff:g>” un “<xliff:g id="TYPE_1">%2$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vai saglabāt vienumus “<xliff:g id="TYPE_0">%1$s</xliff:g>”, “<xliff:g id="TYPE_1">%2$s</xliff:g>” un “<xliff:g id="TYPE_2">%3$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Vai atjaunināt pakalpojumā <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Vai atjaunināt vienumu “<xliff:g id="TYPE">%1$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Vai atjaunināt vienumus “<xliff:g id="TYPE_0">%1$s</xliff:g>” un “<xliff:g id="TYPE_1">%2$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Vai atjaunināt vienumus “<xliff:g id="TYPE_0">%1$s</xliff:g>”, “<xliff:g id="TYPE_1">%2$s</xliff:g>” un “<xliff:g id="TYPE_2">%3$s</xliff:g>” pakalpojumā <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Saglabāt"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nē, paldies"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Atjaunināt"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"paroli"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresi"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredītkartes informāciju"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index db2aa1ee4e45..81421bb8318f 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ബോഡി സെൻസറുകൾ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"നിങ്ങളുടെ ജീവാധാര ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ വിവരങ്ങൾ ആക്സസ് ചെയ്യുക"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"നിങ്ങളുടെ ജീവധാരണ ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യാൻ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ആപ്പിനെ അനുവദിക്കണോ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"സംഗീതം"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"നിങ്ങളുടെ സംഗീതം ആക്സസ് ചെയ്യുക"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> എന്നതിനെ നിങ്ങളുടെ സംഗീതം ആക്സസ് ചെയ്യാൻ അനുവദിക്കണോ?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ഫോട്ടോകളും & വീഡിയോകളും"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"നിങ്ങളുടെ ഫോട്ടോകളും & വീഡിയോകളും"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ഉപയോഗിക്കാനായി വിരലടയാള ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ഫിംഗർപ്രിന്റ് ഹാർഡ്വെയർ ഉപയോഗിക്കുക"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"പ്രാമാണീകരണത്തിനായി വിരലടയാളം ഉപയോഗിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"നിങ്ങളുടെ സംഗീത ശേഖരം റീഡ് ചെയ്യുക"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"നിങ്ങളുടെ സംഗീത ശേഖരം റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"നിങ്ങളുടെ സംഗീത ശേഖരം പരിഷ്കരിക്കുക"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"നിങ്ങളുടെ സംഗീത ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"നിങ്ങളുടെ വീഡിയോ ശേഖരം റീഡ് ചെയ്യുക"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"നിങ്ങളുടെ വീഡിയോ ശേഖരം റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"നിങ്ങളുടെ വീഡിയോ ശേഖരം പരിഷ്കരിക്കുക"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"നിങ്ങളുടെ വീഡിയോ ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം റീഡ് ചെയ്യുക"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്കരിക്കുക"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"വിരലടയാളം ഭാഗികമായി തിരിച്ചറിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"വിരലടയാളം പ്രോസസ്സ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"വിരലടയാള സെൻസറിന് വൃത്തിയില്ല. അത് ശുചിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> എന്നതിനെ <b><xliff:g id="LABEL">%2$s</xliff:g></b>എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> എന്നിവ<b><xliff:g id="LABEL">%3$s</xliff:g></b>എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> എന്നിവ<b><xliff:g id="LABEL">%4$s</xliff:g></b>എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> എന്നതിലേക്ക് അപ്ഡേറ്റ് ചെയ്യണോ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> എന്നതിനെ <b><xliff:g id="LABEL">%2$s</xliff:g></b> എന്നതിലേക്ക് അപ്ഡേറ്റ് ചെയ്യണോ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<b><xliff:g id="LABEL">%3$s</xliff:g></b> എന്നതിലേക്ക് <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> അപ്ഡേറ്റ് ചെയ്യുക?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> എന്നിവയെ <b><xliff:g id="LABEL">%4$s</xliff:g></b> എന്നതിലേക്ക് അപ്ഡേറ്റ് ചെയ്യണോ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"സംരക്ഷിക്കുക"</string> <string name="autofill_save_no" msgid="2625132258725581787">"വേണ്ട, നന്ദി"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"അപ്ഡേറ്റ് ചെയ്യുക"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"പാസ്വേഡ്"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"വിലാസം"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ക്രെഡിറ്റ് കാർഡ്"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 4b0154340531..9c961e2996a2 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"शरीर सेन्सर"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"आपल्या महत्त्वाच्या मापनांविषयी सेंसर डेटा अॅक्सेस करा"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला तुमच्या महत्त्वाच्या लक्षणांविषयीचा सेन्सर डेटा अॅक्सेस करू द्यायचे?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"संगीत"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"तुमचे संगीत अॅक्सेस करा"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ला तुमचे संगीत अॅक्सेस करू द्यायचे का?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"फोटो आणि व्हिडिओ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"तुमचे फोटो आणि व्हिडिओ अॅक्सेस करा"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"वापर करण्याकरिता फिंगरप्रिंट टेम्पलेट जोडण्यासाठी आणि हटविण्यासाठी पद्धती रद्द करण्यास अॅपला अनुमती देते."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"फिंगरप्रिंट हार्डवेअर वापरा"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"प्रमाणीकरणाकरिता फिंगरप्रिंट हार्डवेअरचा वापर करण्यासाठी अॅपला अनुमती देते"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"तुमचा संगीत संग्रह वाचा"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"अॅपला तुमचा संगीत संग्रह वाचण्याची अनुमती देते."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"तुमच्या संगीत संग्रहामध्ये सुधारणा करा"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"अॅपला तुमच्या संगीत संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"तुमचा व्हिडिओ संग्रह वाचा"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"अॅपला तुमचा व्हिडिओ संग्रह वाचण्याची अनुमती देते."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"तुमच्या व्हिडिओ संग्रहामध्ये सुधारणा करा"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"अॅपला तुमच्या व्हिडिओ संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"तुमचा फोटो संग्रह वाचा"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"अॅपला तुमचा फोटो संग्रह वाचण्याची अनुमती देते."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"तुमच्या फोटो संग्रहामध्ये सुधारणा करा"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"अॅपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"अॅपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक फिंगरप्रिंट आढळली. कृपया पुन्हा प्रयत्न करा."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फिंगरप्रिंटवर प्रक्रिया करणे शक्य झाले नाही. कृपया पुन्हा प्रयत्न करा."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"फिंगरप्रिंट सेन्सर खराब आहे. कृपया साफ करा आणि पुन्हा प्रयत्न करा."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<b><xliff:g id="LABEL">%2$s</xliff:g></b>मध्ये <xliff:g id="TYPE">%1$s</xliff:g> सेव्ह करायची?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<b><xliff:g id="LABEL">%3$s</xliff:g></b>मध्ये <xliff:g id="TYPE_0">%1$s</xliff:g> आणि <xliff:g id="TYPE_1">%2$s</xliff:g> सेव्ह करायची?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<b><xliff:g id="LABEL">%4$s</xliff:g></b>मध्ये <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g> सेव्ह करायची?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> वर अपडेट करायचे आहे का?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g><b><xliff:g id="LABEL">%2$s</xliff:g> </b> वर अपडेट करायचे आहे का?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> आणि <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> वर अपडेट करायचा आहे का?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g><b><xliff:g id="LABEL">%4$s</xliff:g></b>वर अपडेट करायचा आहे का?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"सेव्ह करा"</string> <string name="autofill_save_no" msgid="2625132258725581787">"नाही, नको"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करा"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"पत्ता"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 3df4e957a158..939b9a490d7a 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Penderia Badan"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"akses data penderia tentang tanda vital anda"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses data penderia tentang tanda vital anda?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"akses muzik anda"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses muzik anda?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Foto & Video"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"akses foto & video anda"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Benarkan <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> mengakses foto & video anda?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Dapatkan kembali kandungan tetingkap"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Periksa kandungan tetingkap yang berinteraksi dengan anda."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Hidupkan Jelajah melalui Sentuhan"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Membenarkan apl menggunakan kaedah untuk menambahkan dan memadamkan templat cap jari untuk digunakan."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan perkakasan cap jari"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Membenarkan apl menggunakan perkakasan cap jari untuk pengesahan"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"baca koleksi muzik anda"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Membenarkan apl membaca koleksi muzik anda."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ubah suai koleksi muzik anda"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Membenarkan apl mengubah suai koleksi muzik anda."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"baca koleksi video anda"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Membenarkan apl membaca koleksi video anda."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ubah suai koleksi video anda"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Membenarkan apl mengubah suai koleksi video anda."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"baca koleksi foto anda"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Membenarkan apl membaca koleksi foto anda."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ubah suai koleksi foto anda"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Membenarkan apl mengubah suai koleksi foto anda."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"baca lokasi daripada koleksi media anda"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Cap jari separa dikesan. Sila cuba lagi."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses cap jari. Sila cuba lagi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Penderia cap jari kotor. Sila bersihkan dan cuba lagi."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Simpan <xliff:g id="TYPE">%1$s</xliff:g> ke <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Simpan <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> ke <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Simpan <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ke <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Kemas kini ke <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Kemas kini <xliff:g id="TYPE">%1$s</xliff:g> ke <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> ke <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ke <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Simpan"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Tidak, terima kasih"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Kemas kini"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"kata laluan"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"alamat"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kad kredit"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index db3fdd3c7c95..23a73ff031f4 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -301,11 +301,11 @@ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"သင်၏ အဓိကကျသော လက္ခဏာများအကြောင်း အာရုံခံကိရိယာဒေတာကို ရယူသုံးစွဲရန်"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား သင်၏ အရေးကြီးသောလက္ခဏာ အာရုံခံကိရိယာ ဒေတာများကို သုံးခွင့်ပေးလိုပါသလား။"</string> <string name="permgrouplab_aural" msgid="965607064083134896">"တေးဂီတ"</string> - <string name="permgroupdesc_aural" msgid="4870189506255958055">"သင့်တေးဂီတကို ဝင်သုံးသည်"</string> - <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား သင့်တေးဂီတကို ဝင်သုံးခွင့်ပေးလိုပါသလား။"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"သင့်တေးဂီတသို့ ဝင်သည်"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား သင့်တေးဂီတကို ဝင်ခွင့်ပေးလိုပါသလား။"</string> <string name="permgrouplab_visual" msgid="8030190588123857921">"ဓာတ်ပုံနှင့် ဗီဒီယိုများ"</string> - <string name="permgroupdesc_visual" msgid="3415827902566663546">"သင့်ဓာတ်ပုံနှင့် ဗီဒီယိုများကို ဝင်သုံးသည်"</string> - <string name="permgrouprequest_visual" msgid="6907523945030290376">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> အား သင့်ဓာတ်ပုံနှင့် ဗီဒီယိုများကို ဝင်သုံးခွင့်ပေးလိုပါသလား။"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"သင့်ဓာတ်ပုံနှင့် ဗီဒီယိုများသို့ ဝင်သည်"</string> + <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> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index da47ea7a1a50..7d3fe4862221 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Kroppssensorer"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"få tilgang til sensordata om de vitale tegnene dine"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til sensordata om de vitale tegnene dine?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musikk"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"få tilgang til musikken din"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til musikken din?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Bilder og videoer"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"få tilgang til bildene og videoene dine"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vil du gi <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tilgang til bildene og videoene dine?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"hente innhold i vinduer"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Appen analyserer innholdet i vinduer du samhandler med."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"slå på berøringsutforsking"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Lar appen fremkalle metoder for å legge til og slette fingeravtrykkmaler for bruk."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"bruke fingeravtrykkmaskinvare"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Lar appen bruke fingeravtrykkmaskinvare til godkjenning"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"lese musikksamlingen din"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Lar appen lese musikksamlingen din."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"gjøre endringer i musikksamlingen din"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Lar appen gjøre endringer i musikksamlingen din."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"lese videosamlingen din"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Lar appen lese videosamlingen din."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"gjøre endringer i videosamlingen din"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Lar appen gjøre endringer i videosamlingen din."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"lese bildesamlingen din"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Lar appen lese bildesamlingen din."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"gjøre endringer i bildesamlingen din"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Lar appen gjøre endringer i bildesamlingen din."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"lese posisjoner fra mediesamlingen din"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lar appen lese posisjoner fra mediesamlingen din."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Deler av fingeravtrykket er registrert. Prøv på nytt."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtrykksensoren er skitten. Rengjør den og prøv på nytt."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vil du lagre <xliff:g id="TYPE">%1$s</xliff:g> i <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vil du lagre <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> i <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vil du lagre <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> i <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Vil du oppdatere til <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Vil du oppdatere <xliff:g id="TYPE">%1$s</xliff:g> til <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Vil du oppdatere <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> til <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Vil du oppdatere <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g> til <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Lagre"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nei takk"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Oppdater"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"passord"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredittkort"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index c39b7c80bf65..55e62ff0fe50 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"शारीरिक सेन्सर"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"तपाईंको महत्त्वपूर्ण संकेत बारे सेन्सर डेटा पहुँच गर्नुहोस्"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> लाई आफ्ना महत्त्वपूर्ण लक्षणहरूसम्बन्धी सेन्सर डेटामाथि पहुँच राख्न दिने हो?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"सङ्गीत"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"आफ्नो सङ्गीतमाथि पहुँच राख्नुहोस्"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> लाई तपाईंको सङ्गीतमाथि पहुँच राख्न दिने हो?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"तस्बिर तथा भिडियोहरू"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"आफ्नो तस्बिर & भिडियोहरूमाथि पहुँच राख्नुहोस्"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अनुप्रयोगलाई प्रयोगको लागि औठाछाप टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"औठाछाप हार्डवेयर प्रयोग गर्नुहोस्"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"अनुप्रयोगलाई प्रमाणीकरणको लागि औठाछाप हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"आफ्नो सङ्गीतको सङ्ग्रह पढ्नुहोस्"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"यसले अनुप्रयोगलाई तपाईंको सङ्गीतको सङ्ग्रह पढ्न दिन्छ।"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"आफ्नो सङ्गीतको सङ्ग्रह परिमार्जन गर्नुहोस्"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"यसले अनुप्रयोगलाई तपाईंको सङ्गीतको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"आफ्नो भिडियोको सङ्ग्रह पढ्नुहोस्"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"यसले अनुप्रयोगलाई तपाईंको भिडियोको सङ्ग्रह पढ्न दिन्छ।"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"आफ्नो भिडियोको सङ्ग्रह परिमार्जन गर्नुहोस्"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"यसले अनुप्रयोगलाई तपाईंको भिडियोको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"आफ्नो तस्बिरको सङ्ग्रह पढ्नुहोस्"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"यसले अनुप्रयोगलाई तपाईंको तस्बिरको सङ्ग्रह पढ्न दिन्छ।"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"आफ्नो तस्बिरको सङ्ग्रह परिमार्जन गर्नुहोस्"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"यसले अनुप्रयोगलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"यसले अनुप्रयोगलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक औठाछाप पत्ता लाग्यो। कृपया फेरि प्रयास गर्नुहोस्।"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"औठाछाप प्रशोधन गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"औँठाछाप सेन्सर फोहोर छ। कृपया सफा गरेर फेरि प्रयास गर्नुहोस्।"</string> @@ -1918,18 +1898,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> लाई <b><xliff:g id="LABEL">%2$s</xliff:g></b> मा सुरक्षित गर्ने हो?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> र <xliff:g id="TYPE_1">%2$s</xliff:g> लाई <b><xliff:g id="LABEL">%3$s</xliff:g></b> मा सुरक्षित गर्ने हो?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> र <xliff:g id="TYPE_2">%3$s</xliff:g> लाई to <b><xliff:g id="LABEL">%4$s</xliff:g></b> मा सुरक्षित गर्ने हो?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> मा अद्यावधिक गर्ने हो?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> लाई <b><xliff:g id="LABEL">%2$s</xliff:g></b> मा अद्यावधिक गर्ने हो?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> र <xliff:g id="TYPE_1">%2$s</xliff:g> लाई <b><xliff:g id="LABEL">%3$s</xliff:g></b> मा अद्यावधिक गर्ने हो?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> र <xliff:g id="TYPE_2">%3$s</xliff:g> लाई to <b><xliff:g id="LABEL">%4$s</xliff:g></b> मा अद्यावधिक गर्ने हो?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"सुरक्षित गर्नुहोस्"</string> <string name="autofill_save_no" msgid="2625132258725581787">"पर्दैन, धन्यवाद"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"अद्यावधिक गर्नुहोस्"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ठेगाना"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string> diff --git a/core/res/res/values-night/themes_package_installer.xml b/core/res/res/values-night/themes_permission_controller.xml index 0ad2bdcbb52d..0ad2bdcbb52d 100644 --- a/core/res/res/values-night/themes_package_installer.xml +++ b/core/res/res/values-night/themes_permission_controller.xml diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 4d5dd42d260b..b3a2c8144b1d 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ବଡୀ ସେନ୍ସର୍"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ଆପଣଙ୍କ ଗୁରୁତପୂର୍ଣ୍ଣ ସଂକେତଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର୍ ଡାଟା ଆକ୍ସେସ୍ କରେ"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>କୁ ଆପଣଙ୍କ ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଲକ୍ଷଣଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର୍ ଡାଟା ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"ସଙ୍ଗୀତ"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ଆପଣଙ୍କ ସଙ୍ଗୀତ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"ଆପଣଙ୍କ ସଙ୍ଗୀତକୁ ଆକ୍ସେସ୍ କରିବାକୁ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>କୁ ଅନୁମତି ଦେବେ କି?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ଫଟୋ ଏବଂ ଭିଡିଓ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ଆପଣଙ୍କ ଫଟୋ ଏବଂ ଭିଡିଓ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"ଆପଣଙ୍କ ଫଟୋ ଏବଂ ଭିଡିଓକୁ Allow <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ବ୍ୟବହାର କରିବା ପାଇଁ ଆଙ୍ଗୁଠି ଚିହ୍ନ ଯୋଡ଼ିବାକୁ ଓ ଡିଲିଟ୍ କରିବାକୁ ଆପକୁ ବିଧି ଆରମ୍ଭ କରିବାକୁ ଦେଇଥାଏ।"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ସ୍ୱୀକୃତି ପାଇଁ ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରିବାକୁ ଅନୁମତି ଦିଏ"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ଆପଣଙ୍କ ସଙ୍ଗୀତ ସଂଗ୍ରହ ପଢନ୍ତୁ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ଆପଣଙ୍କ ସଂଗୃହିତ ସଙ୍ଗୀତ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ଆପଣଙ୍କ ସଙ୍ଗୀତ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ଆପଣ ଆପଣଙ୍କ ସଙ୍ଗୀତ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ଆପଣଙ୍କ ଭିଡିଓ ସଂଗ୍ରହ ପଢନ୍ତୁ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ଆପଣଙ୍କ ଭିଡିଓ ସଂଗ୍ରହ ପଢିବାକୁ ଆପ୍ଲିକେସନ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ଆପଣଙ୍କ ଭିଡିଓ ସଂଗ୍ରହ ସଂଶୋଧନ କରନ୍ତୁ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ଆପଣଙ୍କ ଭିଡିଓ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପଢନ୍ତୁ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହକୁ ସଂଶୋଧନ କରନ୍ତୁ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଲୋକେସନ୍ଗୁଡିକୁ ପଢନ୍ତୁ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଂଶିକ ଚିହ୍ନଟ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରୋସେସ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନ୍ସର୍ ମଇଳା ହୋଇଯାଇଛି। ଦୟାକରି ସଫା କରନ୍ତୁ ଓ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b>ରେ ସେଭ୍ କରିବେ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> ଏବଂ <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b>ରେ ସେଭ୍ କରିବେ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ଏବଂ <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b>ରେ ସେଭ୍ କରିବେ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>କୁ ଅପ୍ଡେଟ୍ କରିବେ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b>କୁ ଅପ୍ଡେଟ୍ କରିବେ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> ଏବଂ <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b>କୁ ଅପ୍ଡେଟ୍ କରିବେ?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ଏବଂ <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b>କୁ ଅପ୍ଡେଟ୍ କରିବେ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"ସେଭ୍ କରନ୍ତୁ"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ନାଁ, ପଚାରିଥିବାରୁ ଧନ୍ୟବାଦ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"ଅପ୍ଡେଟ୍ କରନ୍ତୁ"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"ପାସୱର୍ଡ୍"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ଠିକଣା"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"କ୍ରେଡିଟ୍ କାର୍ଡ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 96fd692cb392..d581e6b91e55 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ਸਰੀਰ ਸੰਵੇਦਕ"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ਆਪਣੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਚਿੰਨ੍ਹਾਂ ਬਾਰੇ ਸੰਵੇਦਕ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"ਕੀ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਲੱਛਣਾਂ ਸੰਬੰਧੀ ਸੈਂਸਰ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"ਸੰਗੀਤ"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ਤੁਹਾਡੇ ਸੰਗੀਤ ਤੱਕ ਪਹੁੰਚ"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"ਕੀ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਸੰਗੀਤ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ਤੁਹਾਡੀਆਂ ਫ਼ੋਟੋਆਂ ਅਤੇ ਵੀਡੀਓ ਤੱਕ ਪਹੁੰਚ"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ਐਪ ਨੂੰ ਵਰਤੋਂ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰਨ ਅਤੇ ਮਿਟਾਉਣ ਦੀਆਂ ਵਿਧੀਆਂ ਦੀ ਬੇਨਤੀ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਵਰਤੋ"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ਐਪ ਨੂੰ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ਤੁਹਾਡੇ ਸੰਗੀਤ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨਾ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਸੰਗੀਤ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ਤੁਹਾਡੇ ਸੰਗੀਤ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣਾ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਸੰਗੀਤ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ਤੁਹਾਡੇ ਵੀਡੀਓ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨਾ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਵੀਡੀਓ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ਤੁਹਾਡੇ ਵੀਡੀਓ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣਾ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਵੀਡੀਓ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨਾ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣਾ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨਾ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ਅਧੂਰਾ ਫਿੰਗਰਪ੍ਰਿਟ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਕਰ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੰਵੇਦਕ ਗੰਦਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"ਕੀ <xliff:g id="TYPE">%1$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%2$s</xliff:g></b> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"ਕੀ <xliff:g id="TYPE_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="TYPE_1">%2$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%3$s</xliff:g></b> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"ਕੀ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ਅਤੇ <xliff:g id="TYPE_2">%3$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%4$s</xliff:g></b> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"ਕੀ <b><xliff:g id="LABEL">%1$s</xliff:g></b> ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"ਕੀ <xliff:g id="TYPE">%1$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%2$s</xliff:g></b> ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"ਕੀ <xliff:g id="TYPE_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="TYPE_1">%2$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%3$s</xliff:g></b> ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"ਕੀ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ਅਤੇ <xliff:g id="TYPE_2">%3$s</xliff:g> ਨੂੰ <b><xliff:g id="LABEL">%4$s</xliff:g></b> ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"ਰੱਖਿਅਤ ਕਰੋ"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ਨਹੀਂ ਧੰਨਵਾਦ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"ਅੱਪਡੇਟ ਕਰੋ"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"ਪਾਸਵਰਡ"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ਪਤਾ"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ਕ੍ਰੈਡਿਟ ਕਾਰਡ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index dbc577900e6c..6f56e7f116b4 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Czujniki na ciele"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"dostęp do danych czujnika podstawowych funkcji życiowych"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Zezwolić aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do danych z czujnika podstawowych funkcji życiowych?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzyka"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"dostęp do muzyki"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Zezwolić aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do muzyki?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Zdjęcia i filmy"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"dostęp do zdjęć i filmów"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Zezwolić aplikacji <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na dostęp do zdjęć i filmów?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pobieranie zawartości okna"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Sprawdzanie zawartości okna, z którego korzystasz."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Włączenie czytania dotykiem"</string> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Zezwala aplikacji aktywować metody dodawania i usuwania szablonów odcisków palców."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"używanie czytnika linii papilarnych"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Zezwala aplikacji na używanie czytnika linii papilarnych na potrzeby autoryzacji"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"odczytywanie kolekcji muzyki"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Zezwala aplikacji na odczytywanie kolekcji muzyki."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modyfikowanie kolekcji muzyki"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Zezwala aplikacji na modyfikowanie kolekcji muzyki."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"odczytywanie kolekcji filmów"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Zezwala aplikacji na odczytywanie kolekcji filmów."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modyfikowanie kolekcji filmów"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Zezwala aplikacji na modyfikowanie kolekcji filmów."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"odczytywanie kolekcji zdjęć"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Zezwala aplikacji na odczytywanie kolekcji zdjęć."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modyfikowanie kolekcji zdjęć"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Zezwala aplikacji na modyfikowanie kolekcji zdjęć."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"odczytywanie lokalizacji z kolekcji multimediów"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> – zapisać w: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> – zapisać w: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g> – zapisać w: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Zaktualizować do <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Zaktualizować <xliff:g id="TYPE">%1$s</xliff:g> do <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Zaktualizować <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> do <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Zaktualizować <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, i <xliff:g id="TYPE_2">%3$s</xliff:g> do <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Zapisz"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nie, dziękuję"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Zaktualizuj"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"hasło"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"karta kredytowa"</string> diff --git a/core/res/res/values-port/dimens_package_installer.xml b/core/res/res/values-port/dimens_permission_controller.xml index af28713e5ba2..af28713e5ba2 100644 --- a/core/res/res/values-port/dimens_package_installer.xml +++ b/core/res/res/values-port/dimens_permission_controller.xml diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index ab276df48a01..efd68ac6ef2e 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori corporali"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceseze datele de la senzori despre semnele vitale"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să acceseze datele de la senzori despre semnele dvs. vitale?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzică"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"accesați muzica"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să vă acceseze muzica?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotografii și videoclipuri"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"accesați fotografiile și videoclipurile"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Permiteți <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> să vă acceseze fotografiile și videoclipurile?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Analizează conținutul ferestrei"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspectează conținutul unei ferestre cu care interacționați."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activează funcția Explorați prin atingere"</string> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite aplicației să invoce metode pentru a adăuga și pentru a șterge șabloane de amprentă pentru utilizare."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"folosește hardware-ul pentru amprentă"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite aplicației să folosească hardware pentru amprentă pentru autentificare"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"citiți colecția de muzică"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Permite aplicației să vă citească colecția de muzică."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modificați colecția de muzică"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Permite aplicației să vă modifice colecția de muzică."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"citiți colecția de videoclipuri"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Permite aplicației să vă citească colecția de videoclipuri."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modificați colecția de videoclipuri"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Permite aplicației să vă modifice colecția de videoclipuri."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"citiți colecția de fotografii"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Permite aplicației să vă citească colecția de fotografii."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modificați colecția de fotografii"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite aplicației să vă modifice colecția de fotografii."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"citiți locațiile din colecția media"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite aplicației să citească locațiile din colecția dvs. media."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S-a detectat parțial amprenta. Încercați din nou."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Amprenta nu a putut fi procesată. Încercați din nou."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzorul pentru amprente este murdar. Curățați-l și încercați din nou."</string> @@ -1947,18 +1927,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Salvați <xliff:g id="TYPE">%1$s</xliff:g> în <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Salvați <xliff:g id="TYPE_0">%1$s</xliff:g> și <xliff:g id="TYPE_1">%2$s</xliff:g> în <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Salvați <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> și <xliff:g id="TYPE_2">%3$s</xliff:g> în <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Actualizați la <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Actualizați <xliff:g id="TYPE">%1$s</xliff:g> la <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Actualizați <xliff:g id="TYPE_0">%1$s</xliff:g> și <xliff:g id="TYPE_1">%2$s</xliff:g> la <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Actualizați <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> și <xliff:g id="TYPE_2">%3$s</xliff:g> la <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Salvați"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nu, mulțumesc"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Actualizați"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"parolă"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresă"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"card de credit"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index de009a6a3d97..6cc870c86740 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Нательные датчики"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"доступ к данным датчиков о состоянии организма"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к данным датчиков о состоянии организма?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"доступ к музыке"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к музыке?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Фото и видео"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"доступ к фото и видео"</string> + <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> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Приложение сможет добавлять и удалять шаблоны отпечатков пальцев."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"Использование сканера отпечатков"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Приложение сможет использовать сканер отпечатков пальцев для аутентификации."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"доступ к музыкальной коллекции"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Приложение получит доступ к вашей музыкальной коллекции."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"изменение музыкальной коллекции"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Приложение сможет вносить изменения в вашу музыкальную коллекцию."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"доступ к видеоколлекции"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Приложение получит доступ к вашей видеоколлекции."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"изменение видеоколлекции"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Приложение сможет вносить изменения в вашу видеоколлекцию."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"доступ к фотоколлекции"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Приложение получит доступ к вашей фотоколлекции."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"изменение фотоколлекции"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Приложение сможет вносить изменения в вашу фотоколлекцию."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"доступ к геоданным в медиаколлекции"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Отсканирована только часть пальца. Повторите попытку."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не удалось распознать отпечаток. Повторите попытку."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Очистите сканер и повторите попытку."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Сохранить <xliff:g id="TYPE">%1$s</xliff:g> в <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Сохранить <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> в <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Сохранить <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> в <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Обновить данные в <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Обновить данные (<xliff:g id="TYPE">%1$s</xliff:g>) в <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Обновить данные (<xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g>) в <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Обновить данные (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g>) в <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Сохранить"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Нет, спасибо"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Обновить"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"Пароль"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"Адрес"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Банковская карта"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index bdc0c7bb8e60..c263589468f8 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"ශරීර සංවේදක"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ඔබේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත පිවිසෙන්න"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g><b> වෙත ඔබගේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත ප්රවේශ වීමට ඉඩ දෙන්නද?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"සංගීතය"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"ඔබේ සංගීතයට පිවිසෙන්න"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g><b> හට ඔබගේ දින දර්ශනය වෙත පිවිසීමට ඉඩ දෙන්නද?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ඡායාරූප සහ වීඩියෝ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"ඔබගේ ඡායාරූප සහ වීඩියෝ වෙත පිවිසෙන්න"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ඇඟිලි සලකුණු දෘඩාංග භාවිතා කරන්න."</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"අනන්යතාවය තහවුරු කරගැනීමට ඇඟිලි සලකුණු දෘඩාංග භාවිතා කිරීමට මෙම යෙදුමට ඉඩ දෙන්න."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"ඔබගේ සංගීත එකතුව කියවන්න"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ඔබේ සංගීත එකතුව කියවීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"ඔබගේ සංගීත එකතුව වෙනස් කරන්න"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ඔබගේ සංගීත එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"ඔබේ වීඩියෝ එකතුව කියවන්න"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ඔබගේ වීඩියෝ එකතුව කියවීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"ඔබේ වීඩියෝ එකතුව වෙනස් කරන්න"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ඔබගේ වීඩියෝ එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"ඔබේ ඡායාරූප එකතුව කියවන්න"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ඔබගේ ඡායාරූප එකතුව කියවීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"ඔබේ ඡායාරූප එකතුව වෙනස් කරන්න"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවන්න"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string> @@ -1914,18 +1894,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> වෙත සුරකින්නද?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> සහ <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> වෙත සුරකින්නද?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, සහ <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> වෙත සුරකින්නද?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> වෙත යාවත්කාලීන කරන්නද?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> <b><xliff:g id="LABEL">%2$s</xliff:g></b> වෙත යාවත්කාලීන කරන්නද?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> සහ <xliff:g id="TYPE_1">%2$s</xliff:g> <b><xliff:g id="LABEL">%3$s</xliff:g></b> වෙත යාවත්කාලීන කරන්නද?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, සහ <xliff:g id="TYPE_2">%3$s</xliff:g> <b><xliff:g id="LABEL">%4$s</xliff:g></b> වෙත යාවත්කාලීන කරන්නද?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"සුරකින්න"</string> <string name="autofill_save_no" msgid="2625132258725581787">"එපා ස්තූතියි"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"යාවත්කාලීන කරන්න"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"මුරපදය"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ලිපිනය"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ණය කාඩ්පත"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f46771a2a0e2..f3569c984c4f 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -306,18 +306,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Telesné senzory"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"prístup k dátam senzorov vašich životných funkcií"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> používať údaje senzorov o vašich životných funkciách?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Hudba"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"prístup k hudbe"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Chcete povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prístup k hudbe?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotky a videá"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"prístup k fotkám a videám"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Chcete povoliť aplikácii <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prístup k fotkám a videám?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Načítať obsah okna"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Môžete preskúmať obsah okna, s ktorým pracujete."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Zapnúť funkciu Preskúmanie dotykom"</string> @@ -512,34 +506,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Umožňuje aplikácii zavolať metódy, ktoré pridávajú a odstraňujú vzory odtlačkov prstov."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"použiť hardvér na snímanie odtlačkov prstov"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Umožňuje aplikácii používať na overenie totožnosti hardvér na snímanie odtlačkov prstov."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"čítať hudobnú zbierku"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Umožňuje aplikácii čítať hudobnú zbierku."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"upravovať hudobnú zbierku"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Umožňuje aplikácii upravovať hudobnú zbierku."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"čítať zbierku videí"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Umožňuje aplikácii čítať zbierku videí."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"upravovať zbierku videí"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Umožňuje aplikácii upravovať zbierku videí."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"čítať zbierku fotiek"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Umožňuje aplikácii čítať zbierku fotiek."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"upravovať zbierku fotiek"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Umožňuje aplikácii upravovať zbierku fotiek."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"čítať polohy zo zbierky médií"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Podarilo sa rozpoznať iba časť odtlačku prsta. Skúste to znova."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Snímač odtlačkov je špinavý. Vyčistite ho a skúste to znova."</string> @@ -1982,18 +1962,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Uložiť <xliff:g id="TYPE">%1$s</xliff:g> do služby <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Uložiť <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> do služby <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Uložiť <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g> do služby <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Nahrať do služby <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Chcete nahrať <xliff:g id="TYPE">%1$s</xliff:g> do služby <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Chcete nahrať <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> do služby <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Chcete nahrať <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g> do služby <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Uložiť"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nie, vďaka"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Aktualizovať"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"heslo"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditná karta"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 15888fb0f77a..17ec70d9c06e 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensorët e trupit"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"qasu tek të dhënat e sensorëve rreth shenjave të tua jetësore"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Të lejohet që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te të dhënat e sensorëve rreth shenjave të tua jetësore?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Muzika"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"qasu te muzika jote"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Të lejohet që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te muzika jote?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotografitë dhe videot"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"qasu te fotografitë dhe videot e tua"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Të lejohet që <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> të ketë qasje te fotografitë dhe videot e tua?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Nxjerrë përmbajtjen e dritares"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspekton përmbajtjen e dritares me të cilën po ndërvepron."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktivizojë funksionin \"Eksploro me prekje\""</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"E lejon aplikacionin që të aktivizojë metoda për të shtuar dhe për të fshirë shabllonet e gjurmës së gishtit për përdorim."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"përdor harduerin e gjurmës së gishtit"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"E lejon aplikacionin që të përdorë harduerin e gjurmës së gishtit për verifikim"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"lexo koleksionin tënd të muzikës"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Lejon aplikacionin të lexojë koleksionin tënd të muzikës"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"modifiko koleksionin tënd të muzikës"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Lejon aplikacionin të modifikojë koleksionin tënd të muzikës."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"lexo koleksionin tënd të videove"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Lejon aplikacionin të lexojë koleksionin tënd të videove."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"modifiko koleksionin tënd të videove"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Lejon aplikacionin të modifikojë koleksionin tënd të videove."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"lexo koleksionin tënd të fotografive"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Lejon aplikacionin të lexojë koleksionin tënd të fotografive."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"modifiko koleksionin tënd të fotografive"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Lejon aplikacionin të modifikojë koleksionin tënd të fotografive."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"lexo vendndodhjet nga koleksioni yt i medias"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"U zbulua një gjurmë gishti e pjesshme. Provo përsëri."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensori i gjurmës së gishtit nuk është i pastër. Pastroje dhe provo përsëri."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Të ruhet <xliff:g id="TYPE">%1$s</xliff:g> te <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Të ruhen <xliff:g id="TYPE_0">%1$s</xliff:g> dhe <xliff:g id="TYPE_1">%2$s</xliff:g> te <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Të ruhen <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dhe <xliff:g id="TYPE_2">%3$s</xliff:g> te <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Të përditësohet te <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Të përditësohet <xliff:g id="TYPE">%1$s</xliff:g> te <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Të përditësohen <xliff:g id="TYPE_0">%1$s</xliff:g> dhe <xliff:g id="TYPE_1">%2$s</xliff:g> te <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Të përditësohen <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dhe <xliff:g id="TYPE_2">%3$s</xliff:g> te <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Ruaj"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Jo, faleminderit"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Përditëso"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"fjalëkalimi"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"karta e kreditit"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 4c86605228fb..517815dfdc22 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -303,18 +303,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступа подацима сензора о виталним функцијама"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Желите ли да омогућите да <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>приступа подацима сензора о виталним функцијама?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Музика"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"приступ музици"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Желите ли да омогућите да <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> приступа музици?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Слике и видео снимци"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"приступ сликама и видео снимцима"</string> + <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> @@ -509,34 +503,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозвољава апликацији да активира методе за додавање и брисање шаблона отисака прстију који ће се користити."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отиске прстију"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозвољава апликацији да користи хардвер за отиске прстију ради потврде аутентичности"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"читање музичке колекције"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Дозвољава апликацији да чита музичку колекцију."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"измена музичке колекције"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Дозвољава апликацији да мења музичку колекцију."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"читање видео колекције"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Дозвољава апликацији да чита видео колекцију."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"измена видео колекције"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Дозвољава апликацији да мења видео колекцију."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"читање колекције слика"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Дозвољава апликацији да чита колекцију слика."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"измена колекције слика"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Дозвољава апликацији да мења колекцију слика."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"читање локација из медијске колекције"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Дозвољава апликацији да чита локације из медијске колекције."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Пробајте поново."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Пробајте поново."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string> @@ -1947,18 +1927,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Желите ли да сачувате ставку <xliff:g id="TYPE">%1$s</xliff:g> у: <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Желите ли да сачувате ставке <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> у: <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Желите ли да сачувате ставке <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> у: <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Желите ли да ажурирате на <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Желите ли да ажурирате ставку <xliff:g id="TYPE">%1$s</xliff:g> на <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Желите ли да ажурирате ставке <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> на <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Желите ли да ажурирате ставке <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> на <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Сачувај"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Не, хвала"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Ажурирај"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"лозинка"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"адреса"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредитна картица"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 1f3efe08e67f..835f198214d0 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Kroppssensorer"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"få åtkomst till sensordata om dina vitalparametrar"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomst till sensordata om vitalparametrar?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Musik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"åtkomstbehörighet till din musik"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till din musik?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Foton och videor"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"åtkomstbehörighet till dina foton & videor"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vill du ge <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> åtkomstbehörighet till dina foton och videor?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Hämta fönsterinnehåll"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Granska innehållet i ett fönster som du interagerar med."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktivera Explore by touch"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Tillåter att appen anropar metoder för att lägga till och radera fingeravtrycksmallar."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"använda maskinvara för fingeravtryck"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Tillåter att appen använder maskinvara för fingeravtryck vid autentisering"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"läsa av din musiksamling"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Tillåter att appen läser av din musiksamling."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"göra ändringar i din musiksamling"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Tillåter att appen gör ändringar i din musiksamling."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"läsa av din videosamling"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Tillåter att appen läser av din videosamling."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"göra ändringar i din videosamling"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Tillåter att appen gör ändringar i din videosamling."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"läsa av din fotosamling"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Tillåter att appen läser av din fotosamling."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"göra ändringar i din fotosamling"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Tillåter att appen gör ändringar i din fotosamling."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"läsa av platser i din mediesamling"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillåter att appen läser av platser i din mediesamling."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Ofullständigt fingeravtryck. Försök igen."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtryckssensorn är smutsig. Rengör den och försök igen."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Vill du spara <xliff:g id="TYPE">%1$s</xliff:g> i <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Vill du spara <xliff:g id="TYPE_0">%1$s</xliff:g> och <xliff:g id="TYPE_1">%2$s</xliff:g> i <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Vill du spara <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> och <xliff:g id="TYPE_2">%3$s</xliff:g> i <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Vill du uppdatera till <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Vill du uppdatera <xliff:g id="TYPE">%1$s</xliff:g> till <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Vill du uppdatera <xliff:g id="TYPE_0">%1$s</xliff:g> och <xliff:g id="TYPE_1">%2$s</xliff:g> till <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Vill du uppdatera <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> och <xliff:g id="TYPE_2">%3$s</xliff:g> till <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Spara"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Nej tack"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Uppdatera"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"lösenordet"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adressen"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkortet"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 5a7dcca97bd1..c846f08440c2 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -499,9 +499,9 @@ <string name="permlab_useFingerprint" msgid="3150478619915124905">"tumia maunzi ya kitambulisho"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Huruhusu programu kutumia maunzi ya kitambulisho kwa uthibitisho"</string> <string name="permlab_audioRead" msgid="6617225220728465565">"kusoma mkusanyiko muziki wako"</string> - <string name="permdesc_audioRead" msgid="5034032570243484805">"Inaruhusu programu kusoma mkusanyiko wa muziki wako."</string> - <string name="permlab_audioWrite" msgid="2661772059799779292">"kubadilisha mkusanyiko wa muziki wako"</string> - <string name="permdesc_audioWrite" msgid="8888544708166230494">"Inaruhusu programu kubadilisha mkusanyiko wa muziki wako."</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Inaruhusu programu kusoma mkusanyiko wako wa muziki."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"kubadilisha mkusanyiko wako wa muziki"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Inaruhusu programu kubadilisha mkusanyiko wako wa muziki."</string> <string name="permlab_videoRead" msgid="9182618678674737229">"kusoma mkusanyiko wa video zako"</string> <string name="permdesc_videoRead" msgid="7045676429859396194">"Inaruhusu programu kusoma mkusanyiko wa video zako."</string> <string name="permlab_videoWrite" msgid="128769316366746446">"kubadilisha mkusanyiko wa video zako"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index e3f089a762ea..b0d7a4dcb637 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"శరీర సెన్సార్లు"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేస్తుంది"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"సంగీతం"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"మీ సంగీతాన్ని యాక్సెస్ చేయండి"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"మీ సంగీతాన్ని యాక్సెస్ చేయడానికి <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ని అనుమతించాలా?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"ఫోటోలు & వీడియోలు"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"మీ ఫోటోలను & వీడియోలను యాక్సెస్ చేయండి"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"వినియోగం కోసం వేలిముద్ర టెంప్లేట్లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"వేలిముద్ర హార్డ్వేర్ని ఉపయోగించడానికి అనుమతి"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ప్రామాణీకరణ కోసం వేలిముద్ర హార్డ్వేర్ను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"మీ సంగీత సేకరణను చదవండి"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"మీ సంగీత సేకరణను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"మీ సంగీత సేకరణను సవరించండి"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"మీ సంగీత సేకరణని సవరించడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"మీ వీడియో సేకరణను చదవండి"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"మీ వీడియో సేకరణను చదవడానికి యాప్ని అనుమతిస్తుంది."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"మీ వీడియో సేకరణను సవరించండి"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"మీ వీడియో సేకరణను సవరించడానికి యాప్ని అనుమతిస్తుంది."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"మీ ఫోటో సేకరణను చదవండి"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"మీ ఫోటో సేకరణను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"మీ ఫోటో సేకరణను సవరించండి"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"మీ ఫోటో సేకరణను సవరించడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"పాక్షిక వేలిముద్ర గుర్తించబడింది. దయచేసి మళ్లీ ప్రయత్నించండి."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"వేలిముద్రను ప్రాసెస్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"వేలిముద్ర సెన్సార్ మురికిగా ఉంది. దయచేసి శుభ్రపరిచి, మళ్లీ ప్రయత్నించండి."</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>ని <b><xliff:g id="LABEL">%2$s</xliff:g></b>కు సేవ్ చేయాలా?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> మరియు <xliff:g id="TYPE_1">%2$s</xliff:g>లను <b><xliff:g id="LABEL">%3$s</xliff:g></b>కు సేవ్ చేయాలా?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> మరియు <xliff:g id="TYPE_2">%3$s</xliff:g>లను <b><xliff:g id="LABEL">%4$s</xliff:g></b>కు సేవ్ చేయాలా?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>కు అప్డేట్ చేయాలా?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g>ని <b><xliff:g id="LABEL">%2$s</xliff:g></b>కు అప్డేట్ చేయాలా?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> మరియు <xliff:g id="TYPE_1">%2$s</xliff:g>లను <b><xliff:g id="LABEL">%3$s</xliff:g></b>కు అప్డేట్ చేయాలా?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> మరియు <xliff:g id="TYPE_2">%3$s</xliff:g>లను <b><xliff:g id="LABEL">%4$s</xliff:g></b>కు అప్డేట్ చేయాలా?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"సేవ్ చేయి"</string> <string name="autofill_save_no" msgid="2625132258725581787">"వద్దు, ధన్యవాదాలు"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"అప్డేట్ చేయి"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"పాస్వర్డ్"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"చిరునామా"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"క్రెడిట్ కార్డ్"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 537527815318..07107cb02e36 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"เซ็นเซอร์ร่างกาย"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพของคุณ"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"อนุญาตให้ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพไหม"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"เพลง"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"เข้าถึงเพลง"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"อนุญาตให้ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> เข้าถึงเพลงไหม"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"รูปภาพและวิดีโอ"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"เข้าถึงรูปภาพและวิดีโอ"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"อนุญาตให้แอปเรียกใช้วิธีการเพื่อเพิ่มและลบเทมเพลตลายนิ้วมือสำหรับการใช้งาน"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ใช้ฮาร์ดแวร์ลายนิ้วมือ"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"อนุญาตให้แอปใช้ฮาร์ดแวร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"อ่านคอลเล็กชันเพลงของคุณ"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"อนุญาตให้แอปอ่านคอลเล็กชันเพลงของคุณ"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"แก้ไขคอลเล็กชันเพลงของคุณ"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"อนุญาตให้แอปแก้ไขคอลเล็กชันเพลงของคุณ"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"อ่านคอลเล็กชันวิดีโอของคุณ"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"อนุญาตให้แอปอ่านคอลเล็กชันวิดีโอของคุณ"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"แก้ไขคอลเล็กชันวิดีโอของคุณ"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"อนุญาตให้แอปแก้ไขอ่านคอลเล็กชันวิดีโอของคุณ"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"อ่านคอลเล็กชันรูปภาพของคุณ"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"อนุญาตให้แอปอ่านคอลเล็กชันรูปภาพของคุณ"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"แก้ไขคอลเล็กชันรูปภาพของคุณ"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"อนุญาตให้แอปแก้ไขคอลเล็กชันรูปภาพของคุณ"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"อ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ตรวจพบลายนิ้วมือเพียงบางส่วน โปรดลองอีกครั้ง"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ไม่สามารถประมวลผลลายนิ้วมือได้ โปรดลองอีกครั้ง"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"เซ็นเซอร์ลายนิ้วมือไม่สะอาด โปรดทำความสะอาดและลองอีกครั้ง"</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"บันทึก <xliff:g id="TYPE">%1$s</xliff:g> ไปยัง <b><xliff:g id="LABEL">%2$s</xliff:g></b> ใช่ไหม"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"บันทึก <xliff:g id="TYPE_0">%1$s</xliff:g> และ <xliff:g id="TYPE_1">%2$s</xliff:g> ไปยัง <b><xliff:g id="LABEL">%3$s</xliff:g></b> ใช่ไหม"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"บันทึก <xliff:g id="TYPE_0">%1$s</xliff:g> <xliff:g id="TYPE_1">%2$s</xliff:g> และ <xliff:g id="TYPE_2">%3$s</xliff:g> ไปยัง <b><xliff:g id="LABEL">%4$s</xliff:g></b> ใช่ไหม"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"อัปเดตเป็น <b><xliff:g id="LABEL">%1$s</xliff:g></b> ไหม"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"อัปเดต<xliff:g id="TYPE">%1$s</xliff:g>เป็น <b><xliff:g id="LABEL">%2$s</xliff:g></b> ไหม"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"อัปเดต<xliff:g id="TYPE_0">%1$s</xliff:g>และ<xliff:g id="TYPE_1">%2$s</xliff:g>เป็น <b><xliff:g id="LABEL">%3$s</xliff:g></b> ไหม"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"อัปเดต<xliff:g id="TYPE_0">%1$s</xliff:g> <xliff:g id="TYPE_1">%2$s</xliff:g> และ<xliff:g id="TYPE_2">%3$s</xliff:g>เป็น <b><xliff:g id="LABEL">%4$s</xliff:g></b> ไหม"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"บันทึก"</string> <string name="autofill_save_no" msgid="2625132258725581787">"ไม่เป็นไร"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"อัปเดต"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"รหัสผ่าน"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ที่อยู่"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"บัตรเครดิต"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 7ed5859313dc..67991e13a8e1 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Vücut Sensörleri"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"hayati belirtilerinizle ilgili sensör verilerine erişme"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının hayati belirtilerinizle ilgili sensör verilerine erişmesine izin verilsin mi?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Müzik"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"müziğinize erişme"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının müziğinize erişmesine izin veriyor musunuz?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Fotoğraflar ve Videolar"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"fotoğraflarınıza ve videolarınıza erişme"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> uygulamasının fotoğraflarınıza ve videolarınıza erişmesine izin veriyor musunuz?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pencere içeriğini alma"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Etkileşim kurduğunuz pencerenin içeriğini inceler."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Dokunarak Keşfet\'i açma"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Uygulamanın, kullanılacak parmak izi şablonlarını ekleme ve silme yöntemlerini başlatmasına izin verir."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"parmak izi donanımını kullanma"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Uygulamanın kimlik doğrulama için parmak izi donanımını kullanmasına izin verir."</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"müzik koleksiyonunuzu okuma"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Uygulamanın müzik koleksiyonunuzu okumasına izin verir."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"müzik koleksiyonunuzu değiştirme"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Uygulamanın müzik koleksiyonunuzu değiştirmesine izin verir."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"video koleksiyonunuzu okuma"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Uygulamanın video koleksiyonunuzu okumasına izin verir."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"video koleksiyonunuzu değiştirme"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Uygulamanın video koleksiyonunuzu değiştirmesine izin verir."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"fotoğraf koleksiyonunuzu okuma"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Uygulamanın fotoğraf koleksiyonunuzu okumasına izin verir."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"fotoğraf koleksiyonunuzu değiştirme"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Uygulamanın fotoğraf koleksiyonunuzu değiştirmesine izin verir."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"medya koleksiyonunuzdaki konumları okuma"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Parmak izinin tümü algılanamadı. Lütfen tekrar deneyin."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Parmak izi sensörü kirli. Lütfen temizleyin ve tekrar deneyin."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>, <b><xliff:g id="LABEL">%2$s</xliff:g></b> hizmetine kaydedilsin mi?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> ve <xliff:g id="TYPE_1">%2$s</xliff:g>, <b><xliff:g id="LABEL">%3$s</xliff:g></b> hizmetine kaydedilsin mi?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ve <xliff:g id="TYPE_2">%3$s</xliff:g>, <b><xliff:g id="LABEL">%4$s</xliff:g></b> hizmetine kaydedilsin mi?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> hizmetine güncellensin mi?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g>, <b><xliff:g id="LABEL">%2$s</xliff:g></b> hizmetine güncellensin mi?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> ve <xliff:g id="TYPE_1">%2$s</xliff:g>, <b><xliff:g id="LABEL">%3$s</xliff:g></b> hizmetine güncellensin mi?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ve <xliff:g id="TYPE_2">%3$s</xliff:g>, <b><xliff:g id="LABEL">%4$s</xliff:g></b>hizmetine güncellensin mi?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Kaydet"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Hayır, teşekkürler"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Güncelle"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"şifre"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredi kartı"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 3c92c3d7ddbb..fffad9bec9c8 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"باڈی سینسرز"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"اپنی علامات حیات کے متعلق سنسر ڈیٹا تک رسائی حاصل کریں"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> کو آپ کے اہم اشاروں کے متعلق سینسر ڈیٹا تک رسائی کی اجازت دیں؟"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"موسیقی"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"اپنی موسیقی تک رسائی حاصل کریں"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> کو آپ کی موسیقی تک رسائی کی اجازت دیں؟"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"تصاویر اور ویڈیوز"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"اپنی تصاویر اور ویڈیوز تک رسائی حاصل کریں"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ایپ کو استعمال کیلئے فنگر پرنٹ کی تمثیلات شامل کرنے اور حذف کرنے کیلئے طریقوں کو کالعدم قرار دینے کی اجازت دیتا ہے۔"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"فنگر پرنٹ ہارڈ ویئر استعمال کریں"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ایپ کو توثیق کیلئے فنگر پرنٹ ہارڈ ویئر استعمال کرنے کی اجازت دیتا ہے"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"اپنے موسیقی کا مجموعہ پڑھیں"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"ایپ کو آپ کی موسیقی کا مجموعہ پڑھنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"اپنی موسیقی کے مجموعے میں ترمیم کریں"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"ایپ کو آپ کی موسیقی کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"اپنی ویڈیو کا مجموعہ پڑھیں"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"ایپ کو آپ کی ویڈیو کا مجموعہ پڑھنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"اپنی ویڈیو کے مجموعے میں ترمیم کریں"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"ایپ کو آپ کی ویڈیو کے مجموعے میں ترمیم کرنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"اپنی تصویر کا مجموعہ پڑھیں"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"ایپ کو آپ کی تصویر کا مجموعہ پڑھنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"اپنی تصویر کے مجموعے میں ترمیم کریں"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"جزوی فنگر پرنٹ کی شناخت ہوئی۔ براہ کرم دوبارہ کوشش کریں۔"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"فنگر پرنٹ پر کارروائی نہیں کی جا سکی۔ براہ کرم دوبارہ کوشش کریں۔"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"فنگر پرنٹ سینسر گندا ہے۔ براہ کرم صاف کریں اور دوبارہ کوشش کریں۔"</string> @@ -1913,18 +1893,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> کو <b><xliff:g id="LABEL">%2$s</xliff:g></b> میں محفوظ کریں؟"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> اور <xliff:g id="TYPE_1">%2$s</xliff:g> کو <b><xliff:g id="LABEL">%3$s</xliff:g></b> میں محفوظ کریں؟"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>،<xliff:g id="TYPE_1">%2$s</xliff:g>، اور <xliff:g id="TYPE_2">%3$s</xliff:g> کو <b><xliff:g id="LABEL">%4$s</xliff:g></b> میں محفوظ کریں؟"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> میں اپ ڈیٹ کریں؟"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> کو <b><xliff:g id="LABEL">%2$s</xliff:g></b> میں اپ ڈیٹ کریں؟"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> اور <xliff:g id="TYPE_1">%2$s</xliff:g> کو <b><xliff:g id="LABEL">%3$s</xliff:g></b> میں اپ ڈیٹ کریں؟"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>،<xliff:g id="TYPE_1">%2$s</xliff:g>، اور <xliff:g id="TYPE_2">%3$s</xliff:g> کو <b><xliff:g id="LABEL">%4$s</xliff:g></b> میں اپ ڈیٹ کریں؟"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"محفوظ کریں"</string> <string name="autofill_save_no" msgid="2625132258725581787">"نہیں، شکریہ"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"اپ ڈیٹ کریں"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"پاس ورڈ"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"پتہ"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"کریڈٹ کارڈ"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 4e84f620b225..b106ec5bc55d 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Cảm biến cơ thể"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"truy cập dữ liệu cảm biến về dấu hiệu sinh tồn của bạn"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> truy cập vào dữ liệu cảm biến về các dấu hiệu sinh tồn của bạn?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Nhạc"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"sử dụng nhạc"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Bạn có muốn cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sử dụng nhạc không?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Ảnh và video"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"sử dụng ảnh và video"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Bạn có muốn cho phép <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sử dụng ảnh và video không?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Truy xuất nội dung cửa sổ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Kiểm tra nội dung của cửa sổ bạn đang tương tác."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Bật Khám phá bằng cách chạm"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Cho phép ứng dụng gọi các phương pháp để thêm và xóa các mẫu vân tay để sử dụng."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"sử dụng phần cứng vân tay"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Cho phép ứng dụng sử dụng phần cứng vân tay để xác thực"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"đọc bộ sưu tập nhạc"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Cho phép ứng dụng này đọc bộ sưu tập nhạc của bạn."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"sửa đổi bộ sưu tập nhạc"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Cho phép ứng dụng này sửa đổi bộ sưu tập nhạc của bạn."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"đọc bộ sưu tập video"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Cho phép ứng dụng này đọc bộ sưu tập video của bạn."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"sửa đổi bộ sưu tập video"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Cho phép ứng dụng này sửa đổi bộ sưu tập video của bạn."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"đọc bộ sưu tập ảnh"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Cho phép ứng dụng này đọc bộ sưu tập ảnh của bạn."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"sửa đổi bộ sưu tập ảnh"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"đọc vị trí từ bộ sưu tập phương tiện"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Đã phát hiện được một phần vân tay. Vui lòng thử lại."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Không thể xử lý vân tay. Vui lòng thử lại."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Cảm biến vân tay bị bẩn. Hãy làm sạch và thử lại."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Lưu <xliff:g id="TYPE">%1$s</xliff:g> vào <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Lưu <xliff:g id="TYPE_0">%1$s</xliff:g> và <xliff:g id="TYPE_1">%2$s</xliff:g> vào <b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Lưu <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> và <xliff:g id="TYPE_2">%3$s</xliff:g> vào <b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Bạn có muốn cập nhật cho <b><xliff:g id="LABEL">%1$s</xliff:g></b> không?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Bạn có muốn cập nhật <xliff:g id="TYPE">%1$s</xliff:g> cho <b><xliff:g id="LABEL">%2$s</xliff:g></b> không?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Bạn có muốn cập nhật <xliff:g id="TYPE_0">%1$s</xliff:g> và <xliff:g id="TYPE_1">%2$s</xliff:g> cho <b><xliff:g id="LABEL">%3$s</xliff:g></b> không?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Bạn có muốn cập nhật <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> và <xliff:g id="TYPE_2">%3$s</xliff:g> cho <b><xliff:g id="LABEL">%4$s</xliff:g></b> không?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Lưu"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Không, cảm ơn"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Cập nhật"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"mật khẩu"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"địa chỉ"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"thẻ tín dụng"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 0de78ce64de7..5aca3ffff087 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"身体传感器"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"访问与您的生命体征相关的传感器数据"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问与您的生命体征相关的传感器数据吗?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"音乐"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"访问您的音乐"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问您的音乐吗?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"照片和视频"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"访问您的照片和视频"</string> + <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> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允许该应用调用方法来添加和删除可用的指纹模板。"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指纹硬件"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允许该应用使用指纹硬件进行身份验证"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"读取您的音乐收藏"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"允许该应用读取您的音乐收藏。"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"修改您的音乐收藏"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"允许该应用修改您的音乐收藏。"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"读取您的视频收藏"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"允许该应用读取您的视频收藏。"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"修改您的视频收藏"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"允许该应用修改您的视频收藏。"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"读取您的照片收藏"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"允许该应用读取您的照片收藏。"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"修改您的照片收藏"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允许该应用修改您的照片收藏。"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"从您的媒体收藏中读取位置信息"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允许该应用从您的媒体收藏中读取位置信息。"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"仅检测到部分指纹,请重试。"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"无法处理指纹,请重试。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指纹传感器有脏污。请擦拭干净,然后重试。"</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"要将<xliff:g id="TYPE">%1$s</xliff:g>保存到<b><xliff:g id="LABEL">%2$s</xliff:g></b>吗?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"要将<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>保存到<b><xliff:g id="LABEL">%3$s</xliff:g></b>吗?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"要将<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>保存到<b><xliff:g id="LABEL">%4$s</xliff:g></b>吗?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"要更新到<b><xliff:g id="LABEL">%1$s</xliff:g></b>吗?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"要将<xliff:g id="TYPE">%1$s</xliff:g>更新到<b><xliff:g id="LABEL">%2$s</xliff:g></b>吗?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"要将<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>更新到<b><xliff:g id="LABEL">%3$s</xliff:g></b>吗?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"要将<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>更新到<b><xliff:g id="LABEL">%4$s</xliff:g></b>吗?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"保存"</string> <string name="autofill_save_no" msgid="2625132258725581787">"不用了"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"密码"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"地址"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"信用卡"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 91633cd705c1..79c9cc44688f 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -301,11 +301,11 @@ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"存取與您生命體徵相關的感應器資料"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取與您身體機能相關的感應器資料嗎?"</string> <string name="permgrouplab_aural" msgid="965607064083134896">"音樂"</string> - <string name="permgroupdesc_aural" msgid="4870189506255958055">"存取你的音樂"</string> - <string name="permgrouprequest_aural" msgid="6787926123071735620">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取你的音樂嗎?"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"存取您的音樂"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"要允許「<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>」存取您的音樂嗎?"</string> <string name="permgrouplab_visual" msgid="8030190588123857921">"相片和影片"</string> - <string name="permgroupdesc_visual" msgid="3415827902566663546">"存取你的相片和影片"</string> - <string name="permgrouprequest_visual" msgid="6907523945030290376">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<b></b>存取你的相片和影片嗎?"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"存取您的相片和影片"</string> + <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> @@ -500,20 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允許應用程式調用加入和刪除指紋模板的方法以供使用。"</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指紋硬件"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允許應用程式使用指紋硬件驗證"</string> - <string name="permlab_audioRead" msgid="6617225220728465565">"讀取你的音樂收藏"</string> - <string name="permdesc_audioRead" msgid="5034032570243484805">"允許應用程式讀取你的音樂收藏。"</string> - <string name="permlab_audioWrite" msgid="2661772059799779292">"修改你的音樂收藏"</string> - <string name="permdesc_audioWrite" msgid="8888544708166230494">"允許應用程式修改你的音樂收藏。"</string> - <string name="permlab_videoRead" msgid="9182618678674737229">"讀取你的影片收藏"</string> - <string name="permdesc_videoRead" msgid="7045676429859396194">"允許應用程式讀取你的影片收藏。"</string> - <string name="permlab_videoWrite" msgid="128769316366746446">"修改你的影片收藏"</string> - <string name="permdesc_videoWrite" msgid="5448565757490640841">"允許應用程式修改你的影片收藏。"</string> - <string name="permlab_imagesRead" msgid="3015078545742665304">"讀取你的相片收藏"</string> - <string name="permdesc_imagesRead" msgid="3144263806038695580">"允許應用程式讀取你的相片收藏。"</string> - <string name="permlab_imagesWrite" msgid="3391306186247235510">"修改你的相片收藏"</string> - <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改你的相片收藏。"</string> - <string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取你的媒體收藏的位置資訊"</string> - <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string> + <string name="permlab_audioRead" msgid="6617225220728465565">"讀取您的音樂收藏"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"允許應用程式讀取您的音樂收藏。"</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"修改您的音樂收藏"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"允許應用程式修改您的音樂收藏。"</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"讀取您的影片集"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"允許應用程式讀取您的影片集。"</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"修改您的影片集"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"允許應用程式修改您的影片集。"</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"讀取您的相片集"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"允許應用程式讀取您的相片集。"</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"修改您的相片集"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改您的相片集。"</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取媒體集的位置"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取媒體集的位置。"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"只偵測到部分指紋。請再試一次。"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋。請再試一次。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器不乾淨。請清潔後再試一次。"</string> @@ -1892,10 +1892,10 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"要將<xliff:g id="TYPE">%1$s</xliff:g>儲存至「<b><xliff:g id="LABEL">%2$s</xliff:g></b>」嗎?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>儲存至「<b><xliff:g id="LABEL">%3$s</xliff:g></b>」嗎?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>儲存至「<b><xliff:g id="LABEL">%4$s</xliff:g></b>」嗎?"</string> - <string name="autofill_update_title" msgid="4879673117448810818">"要更新為「<xliff:g id="LABEL">%1$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_type" msgid="339733442087186755">"要將<xliff:g id="TYPE">%1$s</xliff:g>更新為「<xliff:g id="LABEL">%2$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>更新為「<xliff:g id="LABEL">%3$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>更新為「<xliff:g id="LABEL">%4$s</xliff:g>」<b></b>嗎?"</string> + <string name="autofill_update_title" msgid="4879673117448810818">"要更新至 <b><xliff:g id="LABEL">%1$s</xliff:g></b> 嗎?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"要將<xliff:g id="TYPE">%1$s</xliff:g>更新至 <b><xliff:g id="LABEL">%2$s</xliff:g></b> 嗎?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>更新至 <b><xliff:g id="LABEL">%3$s</xliff:g></b> 嗎?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>更新至 <b><xliff:g id="LABEL">%4$s</xliff:g></b> 嗎?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"儲存"</string> <string name="autofill_save_no" msgid="2625132258725581787">"不用了,謝謝"</string> <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 219f137a75a7..5143718e526b 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1892,10 +1892,10 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"要將<xliff:g id="TYPE">%1$s</xliff:g>儲存到「<xliff:g id="LABEL">%2$s</xliff:g>」嗎?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>儲存到「<xliff:g id="LABEL">%3$s</xliff:g>」嗎?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>儲存到「<xliff:g id="LABEL">%4$s</xliff:g>」嗎?"</string> - <string name="autofill_update_title" msgid="4879673117448810818">"要更新為「<xliff:g id="LABEL">%1$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_type" msgid="339733442087186755">"要將<xliff:g id="TYPE">%1$s</xliff:g>更新為「<xliff:g id="LABEL">%2$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>更新為「<xliff:g id="LABEL">%3$s</xliff:g>」<b></b>嗎?"</string> - <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"要將<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>更新為「<xliff:g id="LABEL">%4$s</xliff:g>」<b></b>嗎?"</string> + <string name="autofill_update_title" msgid="4879673117448810818">"要更新「<xliff:g id="LABEL">%1$s</xliff:g>」中的資料嗎?<b></b>"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"要更新「<xliff:g id="LABEL">%2$s</xliff:g>」中的<xliff:g id="TYPE">%1$s</xliff:g>嗎?<b></b>"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"要更新「<xliff:g id="LABEL">%3$s</xliff:g>」中的<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>嗎?<b></b>"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"要更新「<xliff:g id="LABEL">%4$s</xliff:g>」中的<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>嗎?<b></b>"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"儲存"</string> <string name="autofill_save_no" msgid="2625132258725581787">"不用了,謝謝"</string> <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 37a2e20426cb..fbe0dc7204ed 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -300,18 +300,12 @@ <string name="permgrouplab_sensors" msgid="416037179223226722">"Izinzwa zomzimba"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"finyelela idatha yesizweli mayelana nezimpawu zakho ezibalulekile"</string> <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Vumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ifinyelele kudatha yenzwa emayelana nezimpawu zakho ezibalulekile?"</string> - <!-- no translation found for permgrouplab_aural (965607064083134896) --> - <skip /> - <!-- no translation found for permgroupdesc_aural (4870189506255958055) --> - <skip /> - <!-- no translation found for permgrouprequest_aural (6787926123071735620) --> - <skip /> - <!-- no translation found for permgrouplab_visual (8030190588123857921) --> - <skip /> - <!-- no translation found for permgroupdesc_visual (3415827902566663546) --> - <skip /> - <!-- no translation found for permgrouprequest_visual (6907523945030290376) --> - <skip /> + <string name="permgrouplab_aural" msgid="965607064083134896">"Umculo"</string> + <string name="permgroupdesc_aural" msgid="4870189506255958055">"finyelela umculo wakho"</string> + <string name="permgrouprequest_aural" msgid="6787926123071735620">"Vumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ifinyelele umculo wakho?"</string> + <string name="permgrouplab_visual" msgid="8030190588123857921">"Izithombe namavidiyo"</string> + <string name="permgroupdesc_visual" msgid="3415827902566663546">"finyelela izithombe zakho namavidiyo"</string> + <string name="permgrouprequest_visual" msgid="6907523945030290376">"Vumela i-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ukuthi ifinyelele kuzithombe zakho namavidiyo?"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Thola okuqukethwe kwewindi"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Hlola okuqukethwe kwewindi ohlanganyela nalo."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Vula ukuhlola ngokuthinta"</string> @@ -506,34 +500,20 @@ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Ivumela uhlelo lokusebenza ukuthi libuyisele izindlela zokungeza nokususa izifanekiso zezigxivizo zeminwe ngokusetshenziswa."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"sebenzisa izingxenyekazi zekhompyutha zezigxivizo zeminwe"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Ivumela uhlelo lokusebenza ukuthi lusebenzise izingxenyekazi zekhompyutha zezigxivizo zeminwe ukuze kuqinisekiswe"</string> - <!-- no translation found for permlab_audioRead (6617225220728465565) --> - <skip /> - <!-- no translation found for permdesc_audioRead (5034032570243484805) --> - <skip /> - <!-- no translation found for permlab_audioWrite (2661772059799779292) --> - <skip /> - <!-- no translation found for permdesc_audioWrite (8888544708166230494) --> - <skip /> - <!-- no translation found for permlab_videoRead (9182618678674737229) --> - <skip /> - <!-- no translation found for permdesc_videoRead (7045676429859396194) --> - <skip /> - <!-- no translation found for permlab_videoWrite (128769316366746446) --> - <skip /> - <!-- no translation found for permdesc_videoWrite (5448565757490640841) --> - <skip /> - <!-- no translation found for permlab_imagesRead (3015078545742665304) --> - <skip /> - <!-- no translation found for permdesc_imagesRead (3144263806038695580) --> - <skip /> - <!-- no translation found for permlab_imagesWrite (3391306186247235510) --> - <skip /> - <!-- no translation found for permdesc_imagesWrite (7073662756617474375) --> - <skip /> - <!-- no translation found for permlab_mediaLocation (8675148183726247864) --> - <skip /> - <!-- no translation found for permdesc_mediaLocation (2237023389178865130) --> - <skip /> + <string name="permlab_audioRead" msgid="6617225220728465565">"funda iqoqo lakho lomculo"</string> + <string name="permdesc_audioRead" msgid="5034032570243484805">"Ivumela uhlelo lokusebenza ukuthi lifunde iqoqo lakho lomculo."</string> + <string name="permlab_audioWrite" msgid="2661772059799779292">"lungisa iqoqo lakho lomculo"</string> + <string name="permdesc_audioWrite" msgid="8888544708166230494">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lomculo."</string> + <string name="permlab_videoRead" msgid="9182618678674737229">"funda iqoqo lakho levidiyo"</string> + <string name="permdesc_videoRead" msgid="7045676429859396194">"Ivumela uhlelo lokusebenza ukuthi lifunde iqoqo lakho levidiyo."</string> + <string name="permlab_videoWrite" msgid="128769316366746446">"lungisa iqoqo lakho levidiyo"</string> + <string name="permdesc_videoWrite" msgid="5448565757490640841">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho levidiyo."</string> + <string name="permlab_imagesRead" msgid="3015078545742665304">"funda iqoqo lakho lesithombe"</string> + <string name="permdesc_imagesRead" msgid="3144263806038695580">"Ivumela uhlelo lokusebenza ukuthi lifunde iqoqo lakho lesithombe."</string> + <string name="permlab_imagesWrite" msgid="3391306186247235510">"lungisa iqoqo lakho lesithombe"</string> + <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lesithombe."</string> + <string name="permlab_mediaLocation" msgid="8675148183726247864">"funda izindawo kusukela kuqoqo lakho lemidiya"</string> + <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Izigxivizo zeminwe ezincane zitholiwe. Sicela uzame futhi."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Inzwa yezigxivizo zeminwe ingcolile. Sicela uyihlanze uphinde uzame futhi."</string> @@ -1912,18 +1892,13 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Londoloza i-<xliff:g id="TYPE">%1$s</xliff:g> ku-<b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Londoloza i-<xliff:g id="TYPE_0">%1$s</xliff:g> ne-<xliff:g id="TYPE_1">%2$s</xliff:g> ku-<b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Londoloza i-<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ne-<xliff:g id="TYPE_2">%3$s</xliff:g> ku-<b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> - <!-- no translation found for autofill_update_title (4879673117448810818) --> - <skip /> - <!-- no translation found for autofill_update_title_with_type (339733442087186755) --> - <skip /> - <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) --> - <skip /> - <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) --> - <skip /> + <string name="autofill_update_title" msgid="4879673117448810818">"Buyekezela ku-<b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"Buyekeza i-<xliff:g id="TYPE">%1$s</xliff:g> ukuya ku-<b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Buyekeza i-<xliff:g id="TYPE_0">%1$s</xliff:g> ne-<xliff:g id="TYPE_1">%2$s</xliff:g> ukuya ku-<b><xliff:g id="LABEL">%3$s</xliff:g></b>?"</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"Buyekeza i-<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ne-<xliff:g id="TYPE_2">%3$s</xliff:g> ukuya ku-<b><xliff:g id="LABEL">%4$s</xliff:g></b>?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"Londoloza"</string> <string name="autofill_save_no" msgid="2625132258725581787">"Cha ngiyabonga"</string> - <!-- no translation found for autofill_update_yes (310358413273276958) --> - <skip /> + <string name="autofill_update_yes" msgid="310358413273276958">"Buyekeza"</string> <string name="autofill_save_type_password" msgid="5288448918465971568">"iphasiwedi"</string> <string name="autofill_save_type_address" msgid="4936707762193009542">"ikheli"</string> <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ikhadi lesikweletu"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c6931aa97a8b..289c898a923c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1868,6 +1868,10 @@ truncate it after committing the transaction. --> <integer name="db_journal_size_limit">524288</integer> + <!-- When opening a database with WAL enabled and if the wal file already exists and larger + than this size in bytes, we'll truncate it. --> + <integer name="db_wal_truncate_size">1048576</integer> + <!-- The database synchronization mode when using the default journal mode. FULL is safest and preserves durability at the cost of extra fsyncs. NORMAL also preserves durability in non-WAL modes and uses checksums to ensure @@ -3517,4 +3521,11 @@ <!-- Whether or not battery saver should be "sticky" when manually enabled. --> <bool name="config_batterySaverStickyBehaviourDisabled">false</bool> + + <!-- Model of potentially misprovisioned devices. If none is specified in an overlay, an + empty string is passed in. --> + <string name="config_misprovisionedDeviceModel" translatable="false"></string> + + <!-- Brand value for attestation of misprovisioned device. --> + <string name="config_misprovisionedBrandValue" translatable="false"></string> </resources> diff --git a/core/res/res/values/styles_package_installer.xml b/core/res/res/values/styles_permission_controller.xml index 339f9c71a57e..339f9c71a57e 100644 --- a/core/res/res/values/styles_package_installer.xml +++ b/core/res/res/values/styles_permission_controller.xml diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7fbad164add1..53588303fcd5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3446,4 +3446,9 @@ <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" /> <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" /> + + <java-symbol type="string" name="config_misprovisionedDeviceModel" /> + <java-symbol type="string" name="config_misprovisionedBrandValue" /> + + <java-symbol type="integer" name="db_wal_truncate_size" /> </resources> diff --git a/core/res/res/values/themes_package_installer.xml b/core/res/res/values/themes_permission_controller.xml index 3bc93cd03a54..3bc93cd03a54 100644 --- a/core/res/res/values/themes_package_installer.xml +++ b/core/res/res/values/themes_permission_controller.xml diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java index 230655de8a00..551a58ed7cb5 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java @@ -62,18 +62,24 @@ public class SQLiteCompatibilityWalFlagsTest { assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE"); assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertEquals(SQLiteGlobal.isCompatibilityWalSupported(), SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true"); assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertEquals(SQLiteGlobal.getWALSyncMode(), SQLiteCompatibilityWalFlags.getWALSyncMode()); assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); + + SQLiteCompatibilityWalFlags.init("truncate_size=1024"); + assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.reset(); SQLiteCompatibilityWalFlags.init("Invalid value"); diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java index c165b6be525e..a2a40e651f49 100644 --- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java @@ -68,12 +68,14 @@ public class IntentForwarderActivityTest { private static final String TYPE_PLAIN_TEXT = "text/plain"; private static UserInfo MANAGED_PROFILE_INFO = new UserInfo(); + static { MANAGED_PROFILE_INFO.id = 10; MANAGED_PROFILE_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE; } private static UserInfo CURRENT_USER_INFO = new UserInfo(); + static { CURRENT_USER_INFO.id = UserHandle.myUserId(); CURRENT_USER_INFO.flags = 0; @@ -84,10 +86,14 @@ public class IntentForwarderActivityTest { private static String sActivityName; private static String sPackageName; - @Mock private IPackageManager mIPm; - @Mock private PackageManager mPm; - @Mock private UserManager mUserManager; - @Mock private ApplicationInfo mApplicationInfo; + @Mock + private IPackageManager mIPm; + @Mock + private PackageManager mPm; + @Mock + private UserManager mUserManager; + @Mock + private ApplicationInfo mApplicationInfo; @Rule public ActivityTestRule<IntentForwarderWrapperActivity> mActivityRule = @@ -264,8 +270,8 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_notWhitelisted() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SEND) - .setType(TYPE_PLAIN_TEXT); + .setAction(Intent.ACTION_SEND) + .setType(TYPE_PLAIN_TEXT); mActivityRule.launchActivity(intent); @@ -279,8 +285,8 @@ public class IntentForwarderActivityTest { sActivityName = ResolverActivity.class.getName(); sPackageName = "android"; Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SEND) - .setType(TYPE_PLAIN_TEXT); + .setAction(Intent.ACTION_SEND) + .setType(TYPE_PLAIN_TEXT); mActivityRule.launchActivity(intent); @@ -292,7 +298,31 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_callIntent_call() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_CALL); + .setAction(Intent.ACTION_CALL); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_callIntent_callPrivileged() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_CALL_PRIVILEGED); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_callIntent_callEmergency() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_CALL_EMERGENCY); mActivityRule.launchActivity(intent); @@ -304,7 +334,7 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_callIntent_dial() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_DIAL); + .setAction(Intent.ACTION_DIAL); mActivityRule.launchActivity(intent); @@ -316,7 +346,7 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_callIntent_notCallOrDial() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_ALARM_CHANGED); + .setAction(Intent.ACTION_ALARM_CHANGED); mActivityRule.launchActivity(intent); @@ -325,11 +355,25 @@ public class IntentForwarderActivityTest { } @Test + public void shouldSkipDisclosure_callIntent_actionViewTel() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("tel", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test public void shouldSkipDisclosure_textMessageIntent_sms() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SENDTO) - .setData(Uri.fromParts("sms", PHONE_NUMBER, null)); + .setAction(Intent.ACTION_SENDTO) + .setData(Uri.fromParts("sms", PHONE_NUMBER, null)); mActivityRule.launchActivity(intent); @@ -341,8 +385,8 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_textMessageIntent_smsto() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SENDTO) - .setData(Uri.fromParts("smsto", PHONE_NUMBER, null)); + .setAction(Intent.ACTION_SENDTO) + .setData(Uri.fromParts("smsto", PHONE_NUMBER, null)); mActivityRule.launchActivity(intent); @@ -354,8 +398,8 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_textMessageIntent_mms() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SENDTO) - .setData(Uri.fromParts("mms", PHONE_NUMBER, null)); + .setAction(Intent.ACTION_SENDTO) + .setData(Uri.fromParts("mms", PHONE_NUMBER, null)); mActivityRule.launchActivity(intent); @@ -367,8 +411,64 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_textMessageIntent_mmsto() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SENDTO) - .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null)); + .setAction(Intent.ACTION_SENDTO) + .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_textMessageIntent_actionViewSms() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("sms", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_textMessageIntent_actionViewSmsto() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("smsto", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_textMessageIntent_actionViewMms() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("mms", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector, never()).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_textMessageIntent_actionViewMmsto() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("mmsto", PHONE_NUMBER, null)); mActivityRule.launchActivity(intent); @@ -380,8 +480,36 @@ public class IntentForwarderActivityTest { public void shouldSkipDisclosure_textMessageIntent_invalidUri() throws RemoteException { setupShouldSkipDisclosureTest(); Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) - .setAction(Intent.ACTION_SENDTO) - .setData(Uri.fromParts("invalid", PHONE_NUMBER, null)); + .setAction(Intent.ACTION_SENDTO) + .setData(Uri.fromParts("invalid", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_viewBrowsableIntent_invalidUri() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("invalid", PHONE_NUMBER, null)); + + mActivityRule.launchActivity(intent); + + verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt()); + verify(sInjector).showToast(anyInt(), anyInt()); + } + + @Test + public void shouldSkipDisclosure_viewBrowsableIntent_normalUrl() throws RemoteException { + setupShouldSkipDisclosureTest(); + Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class) + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("http", "apache.org", null)); mActivityRule.launchActivity(intent); @@ -401,10 +529,11 @@ public class IntentForwarderActivityTest { when(mUserManager.getProfiles(anyInt())).thenReturn(profiles); // Intent can be forwarded. when(mIPm.canForwardTo( - any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true); + any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true); } public static class IntentForwarderWrapperActivity extends IntentForwarderActivity { + private Intent mStartActivityIntent; private int mUserIdActivityLaunchedIn; diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java index a8094ead2972..613de45173d6 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java @@ -24,6 +24,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; @@ -302,6 +303,113 @@ public class BatteryStatsImplTest { assertArrayEquals(expected, mBatteryStatsImpl.addCpuTimes(timesA, timesB)); } + @Test + public void testMulticastWakelockAcqRel() { + final int testUid = 10032; + final int acquireTimeMs = 1000; + final int releaseTimeMs = 1005; + final int currentTimeMs = 1011; + + mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + + // Create a Uid Object + final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid); + assertNotNull(u); + + // Acquire and release the lock + u.noteWifiMulticastEnabledLocked(acquireTimeMs); + u.noteWifiMulticastDisabledLocked(releaseTimeMs); + + // Get the total acquisition time + long totalTime = u.getWifiMulticastTime(currentTimeMs*1000, + BatteryStats.STATS_SINCE_UNPLUGGED); + assertEquals("Miscalculations of Multicast wakelock acquisition time", + (releaseTimeMs - acquireTimeMs) * 1000, totalTime); + } + + @Test + public void testMulticastWakelockAcqNoRel() { + final int testUid = 10032; + final int acquireTimeMs = 1000; + final int currentTimeMs = 1011; + + mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + + // Create a Uid Object + final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid); + assertNotNull(u); + + // Acquire the lock + u.noteWifiMulticastEnabledLocked(acquireTimeMs); + + // Get the total acquisition time + long totalTime = u.getWifiMulticastTime(currentTimeMs*1000, + BatteryStats.STATS_SINCE_UNPLUGGED); + assertEquals("Miscalculations of Multicast wakelock acquisition time", + (currentTimeMs - acquireTimeMs) * 1000, totalTime); + } + + @Test + public void testMulticastWakelockAcqAcqRelRel() { + final int testUid = 10032; + final int acquireTimeMs_1 = 1000; + final int acquireTimeMs_2 = 1002; + + final int releaseTimeMs_1 = 1005; + final int releaseTimeMs_2 = 1009; + final int currentTimeMs = 1011; + + mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + + // Create a Uid Object + final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid); + assertNotNull(u); + + // Acquire and release the lock (twice in nested way) + u.noteWifiMulticastEnabledLocked(acquireTimeMs_1); + u.noteWifiMulticastEnabledLocked(acquireTimeMs_2); + + u.noteWifiMulticastDisabledLocked(releaseTimeMs_1); + u.noteWifiMulticastDisabledLocked(releaseTimeMs_2); + + // Get the total acquisition time + long totalTime = u.getWifiMulticastTime(currentTimeMs*1000, + BatteryStats.STATS_SINCE_UNPLUGGED); + assertEquals("Miscalculations of Multicast wakelock acquisition time", + (releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime); + } + + @Test + public void testMulticastWakelockAcqRelAcqRel() { + final int testUid = 10032; + final int acquireTimeMs_1 = 1000; + final int acquireTimeMs_2 = 1005; + + final int releaseTimeMs_1 = 1002; + final int releaseTimeMs_2 = 1009; + final int currentTimeMs = 1011; + + mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + + // Create a Uid Object + final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid); + assertNotNull(u); + + // Acquire and release the lock (twice) + u.noteWifiMulticastEnabledLocked(acquireTimeMs_1); + u.noteWifiMulticastDisabledLocked(releaseTimeMs_1); + + u.noteWifiMulticastEnabledLocked(acquireTimeMs_2); + u.noteWifiMulticastDisabledLocked(releaseTimeMs_2); + + // Get the total acquisition time + long totalTime = u.getWifiMulticastTime(currentTimeMs*1000, + BatteryStats.STATS_SINCE_UNPLUGGED); + assertEquals("Miscalculations of Multicast wakelock acquisition time", + ((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2)) + * 1000, totalTime); + } + private void addIsolatedUid(int parentUid, int childUid) { final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid); u.addIsolatedUid(childUid); diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm index d0565ca7e876..1ab4c6385ac1 100644 --- a/data/keyboards/Generic.kcm +++ b/data/keyboards/Generic.kcm @@ -540,7 +540,7 @@ key BUTTON_SELECT { } key BUTTON_MODE { - base: fallback MENU + base: fallback HOME } key BUTTON_1 { diff --git a/data/keyboards/Vendor_045e_Product_02e0.kl b/data/keyboards/Vendor_045e_Product_02e0.kl index 1012fb1eb28d..1dd8e157c5a7 100644 --- a/data/keyboards/Vendor_045e_Product_02e0.kl +++ b/data/keyboards/Vendor_045e_Product_02e0.kl @@ -56,4 +56,4 @@ key 0x136 BUTTON_SELECT key 0x137 BUTTON_START # Xbox key -key 0x8b HOME
\ No newline at end of file +key 0x8b BUTTON_MODE
\ No newline at end of file diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 7fa748461c2d..52806423c336 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -1008,7 +1008,10 @@ public class Typeface { SystemFonts.getAliases()); sSystemFontMap = Collections.unmodifiableMap(systemFontMap); - setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); + // We can't assume DEFAULT_FAMILY available on Roboletric. + if (sSystemFontMap.containsKey(DEFAULT_FAMILY)) { + setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); + } // Set up defaults and typefaces exposed in public API DEFAULT = create((String) null, 0); diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java new file mode 100644 index 000000000000..40ba5d159261 --- /dev/null +++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java @@ -0,0 +1,271 @@ +/* + * 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.graphics.drawable; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.content.pm.ActivityInfo; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.util.MathUtils; + +/** + * A Drawable that manages a {@link ColorDrawable} to make it stateful and backed by a + * {@link ColorStateList}. + */ +public class ColorStateListDrawable extends Drawable implements Drawable.Callback { + private ColorDrawable mColorDrawable; + private ColorStateListDrawableState mState; + + public ColorStateListDrawable() { + mState = new ColorStateListDrawableState(); + initializeColorDrawable(); + } + + public ColorStateListDrawable(ColorStateList colorStateList) { + mState = new ColorStateListDrawableState(); + initializeColorDrawable(); + setColorStateList(colorStateList); + } + + @Override + public void draw(Canvas canvas) { + mColorDrawable.draw(canvas); + } + + @Override + @IntRange(from = 0, to = 255) + public int getAlpha() { + return mColorDrawable.getAlpha(); + } + + @Override + public boolean isStateful() { + return mState.isStateful(); + } + + @Override + public boolean hasFocusStateSpecified() { + return mState.hasFocusStateSpecified(); + } + + @Override + public @NonNull Drawable getCurrent() { + return mColorDrawable; + } + + @Override + public void applyTheme(Resources.Theme t) { + super.applyTheme(t); + + if (mState.mColor != null) { + setColorStateList(mState.mColor.obtainForTheme(t)); + } + + if (mState.mTint != null) { + setTintList(mState.mTint.obtainForTheme(t)); + } + } + + @Override + public boolean canApplyTheme() { + return super.canApplyTheme() || mState.canApplyTheme(); + } + + @Override + public void setAlpha(@IntRange(from = 0, to = 255) int alpha) { + mState.mAlpha = alpha; + onStateChange(getState()); + } + + /** + * Remove the alpha override, reverting to the alpha defined on each color in the + * {@link ColorStateList}. + */ + public void clearAlpha() { + mState.mAlpha = -1; + onStateChange(getState()); + } + + @Override + public void setTintList(ColorStateList tint) { + mState.mTint = tint; + mColorDrawable.setTintList(tint); + onStateChange(getState()); + } + + @Override + public void setTintMode(PorterDuff.Mode tintMode) { + mState.mTintMode = tintMode; + mColorDrawable.setTintMode(tintMode); + onStateChange(getState()); + } + + @Override + public ColorFilter getColorFilter() { + return mColorDrawable.getColorFilter(); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mColorDrawable.setColorFilter(colorFilter); + } + + @Override + public @PixelFormat.Opacity int getOpacity() { + return mColorDrawable.getOpacity(); + } + + @Override + protected boolean onStateChange(int[] state) { + if (mState.mColor != null) { + int color = mState.mColor.getColorForState(state, mState.mColor.getDefaultColor()); + + if (mState.mAlpha != -1) { + color = color & 0xFFFFFF | MathUtils.constrain(mState.mAlpha, 0, 255) << 24; + } + + if (color != mColorDrawable.getColor()) { + mColorDrawable.setColor(color); + mColorDrawable.setState(state); + return true; + } else { + return mColorDrawable.setState(state); + } + } else { + return false; + } + } + + @Override + public void invalidateDrawable(Drawable who) { + final Callback callback = getCallback(); + + if (callback != null) { + callback.invalidateDrawable(who); + } + } + + @Override + public void scheduleDrawable(Drawable who, Runnable what, long when) { + final Callback callback = getCallback(); + + if (callback != null) { + callback.scheduleDrawable(who, what, when); + } + } + + @Override + public void unscheduleDrawable(Drawable who, Runnable what) { + final Callback callback = getCallback(); + + if (callback != null) { + callback.unscheduleDrawable(who, what); + } + } + + @Override + public ConstantState getConstantState() { + return mState; + } + + /** + * Returns the ColorStateList backing this Drawable, or a new ColorStateList of the default + * ColorDrawable color if one hasn't been defined yet. + * + * @return a ColorStateList + */ + public @NonNull ColorStateList getColorStateList() { + if (mState.mColor == null) { + return ColorStateList.valueOf(mColorDrawable.getColor()); + } else { + return mState.mColor; + } + } + + /** + * Replace this Drawable's ColorStateList. It is not copied, so changes will propagate on the + * next call to {@link #setState(int[])}. + * + * @param colorStateList A color state list to attach. + */ + public void setColorStateList(ColorStateList colorStateList) { + mState.mColor = colorStateList; + onStateChange(getState()); + } + + static final class ColorStateListDrawableState extends ConstantState { + ColorStateList mColor = null; + ColorStateList mTint = null; + int mAlpha = -1; + PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; + @ActivityInfo.Config int mChangingConfigurations = 0; + + ColorStateListDrawableState() { + } + + + @Override + public Drawable newDrawable() { + return new ColorStateListDrawable(this); + } + + @Override + public @ActivityInfo.Config int getChangingConfigurations() { + return mChangingConfigurations + | (mColor != null ? mColor.getChangingConfigurations() : 0) + | (mTint != null ? mTint.getChangingConfigurations() : 0); + } + + public boolean isStateful() { + return (mColor != null && mColor.isStateful()) + || (mTint != null && mTint.isStateful()); + } + + public boolean hasFocusStateSpecified() { + return (mColor != null && mColor.hasFocusStateSpecified()) + || (mTint != null && mTint.hasFocusStateSpecified()); + } + + @Override + public boolean canApplyTheme() { + return (mColor != null && mColor.canApplyTheme()) + || (mTint != null && mTint.canApplyTheme()); + } + } + + private ColorStateListDrawable(ColorStateListDrawableState state) { + mState = state; + initializeColorDrawable(); + } + + private void initializeColorDrawable() { + mColorDrawable = new ColorDrawable(); + mColorDrawable.setCallback(this); + + if (mState.mTint != null) { + mColorDrawable.setTintList(mState.mTint); + } + + if (mState.mTintMode != DEFAULT_TINT_MODE) { + mColorDrawable.setTintMode(mState.mTintMode); + } + } +} diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index 1be8309bcf5a..3d2a2718a9c8 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -22,9 +22,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; +import android.content.res.Resources; import android.os.Build; import android.security.KeyStore; -import android.security.KeyStoreException; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; @@ -117,6 +117,37 @@ public abstract class AttestationUtils { @NonNull public static KeymasterArguments prepareAttestationArguments(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { + return prepareAttestationArguments(context, idTypes,attestationChallenge, Build.BRAND); + } + + /** + * Prepares Keymaster Arguments with attestation data for misprovisioned Pixel 2 device. + * See http://go/keyAttestationFailure and http://b/69471841 for more info. + * @hide should only be used by KeyChain. + */ + @NonNull public static KeymasterArguments prepareAttestationArgumentsIfMisprovisioned( + Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws + DeviceIdAttestationException { + if (!isPotentiallyMisprovisionedDevice(context)) { + return null; + } + Resources resources = context.getResources(); + String misprovisionedBrand = resources.getString( + com.android.internal.R.string.config_misprovisionedBrandValue); + return prepareAttestationArguments( + context, idTypes, attestationChallenge, misprovisionedBrand); + } + + @NonNull private static boolean isPotentiallyMisprovisionedDevice(Context context) { + Resources resources = context.getResources(); + String misprovisionedModel = resources.getString( + com.android.internal.R.string.config_misprovisionedDeviceModel); + return (Build.MODEL.equals(misprovisionedModel)); + } + + @NonNull private static KeymasterArguments prepareAttestationArguments(Context context, + @NonNull int[] idTypes, @NonNull byte[] attestationChallenge, String brand) throws + DeviceIdAttestationException { // Check method arguments, retrieve requested device IDs and prepare attestation arguments. if (attestationChallenge == null) { throw new NullPointerException("Missing attestation challenge"); @@ -169,7 +200,7 @@ public abstract class AttestationUtils { } } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND, - Build.BRAND.getBytes(StandardCharsets.UTF_8)); + brand.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE, Build.DEVICE.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT, diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index e39926beee41..bba36bcba804 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -136,6 +136,7 @@ cc_test { "tests/ByteBucketArray_test.cpp", "tests/Config_test.cpp", "tests/ConfigLocale_test.cpp", + "tests/DynamicRefTable_test.cpp", "tests/Idmap_test.cpp", "tests/LoadedArsc_test.cpp", "tests/ResourceUtils_test.cpp", diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index fc625bbaf72d..843c1461e21b 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -74,6 +74,7 @@ const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; +const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 861dc0f3879c..402e390d803f 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -6960,6 +6960,11 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { uint32_t res = *resId; size_t packageId = Res_GETPACKAGE(res) + 1; + if (!Res_VALIDID(res)) { + // Cannot look up a null or invalid id, so no lookup needs to be done. + return NO_ERROR; + } + if (packageId == APP_PACKAGE_ID && !mAppAsLib) { // No lookup needs to be done, app package IDs are absolute. return NO_ERROR; @@ -6993,25 +6998,17 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { } status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { - uint8_t resolvedType = Res_value::TYPE_REFERENCE; - switch (value->dataType) { - case Res_value::TYPE_ATTRIBUTE: - resolvedType = Res_value::TYPE_ATTRIBUTE; - // fallthrough - case Res_value::TYPE_REFERENCE: - if (!mAppAsLib) { - return NO_ERROR; - } + uint8_t resolvedType; - // If the package is loaded as shared library, the resource reference - // also need to be fixed. - break; - case Res_value::TYPE_DYNAMIC_ATTRIBUTE: + if (value->dataType == Res_value::TYPE_ATTRIBUTE + || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) { resolvedType = Res_value::TYPE_ATTRIBUTE; - // fallthrough - case Res_value::TYPE_DYNAMIC_REFERENCE: - break; - default: + + } else if (value->dataType == Res_value::TYPE_REFERENCE + || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) { + resolvedType = Res_value::TYPE_REFERENCE; + + } else { return NO_ERROR; } diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index 08da7319de85..cdb87bcb8e11 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -61,6 +61,7 @@ public: static const char* IDMAP_BIN; static const char* OVERLAY_DIR; static const char* PRODUCT_OVERLAY_DIR; + static const char* PRODUCT_SERVICES_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp new file mode 100644 index 000000000000..df44e343b2b4 --- /dev/null +++ b/libs/androidfw/tests/DynamicRefTable_test.cpp @@ -0,0 +1,74 @@ +/* + * 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 "androidfw/ResourceTypes.h" +#include "utils/String8.h" + +#include "gtest/gtest.h" +namespace android { + +TEST(DynamicRefTableTest, LookupSharedLibSelfReferences) { + // Shared library + DynamicRefTable shared_table(0x02, /* appAsLib */ false); + shared_table.addMapping(0x00, 0x02); + Res_value value; + value.dataType = Res_value::TYPE_REFERENCE; + value.data = 0x00010000; + ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x02010000); + + // App loaded as a shared library + DynamicRefTable shared_app_table(0x02, /* appAsLib */ true); + shared_app_table.addMapping(0x7f, 0x02); + Res_value value2; + value2.dataType = Res_value::TYPE_REFERENCE; + value2.data = 0x7f010000; + ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x02010000); +}; + +TEST(DynamicRefTableTest, LookupDynamicReferences) { + // Shared library + DynamicRefTable shared_table(0x2, /* appAsLib */ false); + shared_table.addMapping(0x00, 0x02); + shared_table.addMapping(0x03, 0x05); + Res_value value; + value.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value.data = 0x03010000; + ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x05010000); + + // App loaded as a shared library + DynamicRefTable shared_app_table(0x2, /* appAsLib */ true); + shared_app_table.addMapping(0x03, 0x05); + shared_app_table.addMapping(0x7f, 0x2); + Res_value value2; + value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value2.data = 0x03010000; + ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x05010000); + + // Regular application + DynamicRefTable app_table(0x7f, /* appAsLib */ false); + app_table.addMapping(0x03, 0x05); + Res_value value3; + value3.dataType = Res_value::TYPE_REFERENCE; + value3.data = 0x03010000; + ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR); + EXPECT_EQ(value3.data, 0x05010000); +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index b37f2cfe7fee..f2766d6a5b6e 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -39,7 +39,7 @@ public: virtual void onError(const std::string& message) = 0; protected: - ~ErrorHandler() {} + virtual ~ErrorHandler() {} }; class TreeObserver { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 4a1fd9ee3d47..62f704b08771 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -59,7 +59,7 @@ public: virtual void doFrame() = 0; protected: - ~IFrameCallback() {} + virtual ~IFrameCallback() {} }; struct VsyncSource { diff --git a/media/OWNERS b/media/OWNERS index 182f661fcfff..1ae2a7bd8dee 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -1,5 +1,8 @@ elaurent@google.com etalvala@google.com +gkasten@google.com +hunga@google.com +jmtrivi@google.com lajos@google.com marcone@google.com sungsoo@google.com diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 76fc9e350ecc..d45acdfa627e 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -405,7 +405,7 @@ import java.util.Map; <p> The codec in turn will return a read-only output buffer via the {@link Callback#onOutputBufferAvailable onOutputBufferAvailable} callback in asynchronous mode, or in - response to a {@link #dequeueOutputBuffer dequeuOutputBuffer} call in synchronous mode. After the + response to a {@link #dequeueOutputBuffer dequeueOutputBuffer} call in synchronous mode. After the output buffer has been processed, call one of the {@link #releaseOutputBuffer releaseOutputBuffer} methods to return the buffer to the codec. <p> diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index e183a6b977f5..aa78b0d0721d 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -712,6 +712,12 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener public abstract void setNextDataSources(@NonNull List<DataSourceDesc> dsds); /** + * Removes all data sources pending to be played. + */ + // This is an asynchronous call. + public abstract void clearNextDataSources(); + + /** * Gets the current data source as described by a DataSourceDesc. * * @return the current DataSourceDesc @@ -2066,6 +2072,11 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener */ public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; + /** The player just completed a call {@link #clearNextDataSources}. + * @see EventCallback#onCallCompleted + */ + public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30; + /** The player just completed a call {@link #setBufferingParams}. * @see EventCallback#onCallCompleted * @hide @@ -2109,6 +2120,7 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener CALL_COMPLETED_SET_SURFACE, CALL_COMPLETED_SET_SYNC_PARAMS, CALL_COMPLETED_SKIP_TO_NEXT, + CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, CALL_COMPLETED_SET_BUFFERING_PARAMS, CALL_COMPLETED_SET_VIDEO_SCALING_MODE, CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index 95ba00fa617b..c06b97b65735 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -210,22 +210,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { @Override void process() { stayAwake(true); - - // TODO: remove this block when native code sends MEDIA_INFO_DATA_SOURCE_START - // when pipeline is created. - if (getState() == PLAYER_STATE_PREPARED) { - final DataSourceDesc dsd; - synchronized (mSrcLock) { - dsd = mCurrentDSD; - } - synchronized (mEventCbLock) { - for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { - cb.first.execute(() -> cb.second.onInfo( - MediaPlayer2Impl.this, dsd, MEDIA_INFO_DATA_SOURCE_START, 0)); - } - } - } - _start(); } }); @@ -451,6 +435,23 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } @Override + public void clearNextDataSources() { + addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) { + @Override + void process() { + synchronized (mSrcLock) { + if (mNextDSDs != null) { + mNextDSDs.clear(); + mNextDSDs = null; + } + mNextSrcId = mSrcIdGenerator++; + mNextSourceState = NEXT_SOURCE_STATE_INIT; + } + } + }); + } + + @Override public @NonNull DataSourceDesc getCurrentDataSource() { synchronized (mSrcLock) { return mCurrentDSD; @@ -1646,6 +1647,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { synchronized (mDrmEventCbLock) { mDrmEventCallbackRecords.clear(); } + synchronized (mSrcLock) { + if (mNextDSDs != null) { + mNextDSDs.clear(); + mNextDSDs = null; + } + mNextSrcId = mSrcIdGenerator++; + mNextSourceState = NEXT_SOURCE_STATE_INIT; + } stayAwake(false); _reset(); diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 9c5813521545..e67b100d840d 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -266,6 +266,12 @@ public class MtpDatabase implements AutoCloseable { if (MtpDatabase.this.mServer != null) MtpDatabase.this.mServer.sendObjectRemoved(id); } + + @Override + public void sendObjectInfoChanged(int id) { + if (MtpDatabase.this.mServer != null) + MtpDatabase.this.mServer.sendObjectInfoChanged(id); + } }, subDirectories == null ? null : Sets.newHashSet(subDirectories)); initDeviceProperties(context); diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java index 8af5ff7ac1fc..a555d37df40d 100644 --- a/media/java/android/mtp/MtpServer.java +++ b/media/java/android/mtp/MtpServer.java @@ -77,6 +77,10 @@ public class MtpServer implements Runnable { native_send_object_removed(handle); } + public void sendObjectInfoChanged(int handle) { + native_send_object_info_changed(handle); + } + public void sendDevicePropertyChanged(int property) { native_send_device_property_changed(property); } @@ -106,6 +110,7 @@ public class MtpServer implements Runnable { private native final void native_cleanup(); private native final void native_send_object_added(int handle); private native final void native_send_object_removed(int handle); + private native final void native_send_object_info_changed(int handle); private native final void native_send_device_property_changed(int property); private native final void native_add_storage(MtpStorage storage); private native final void native_remove_storage(int storageId); diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java index 756e942c33c5..f14e7d704ea1 100644 --- a/media/java/android/mtp/MtpStorageManager.java +++ b/media/java/android/mtp/MtpStorageManager.java @@ -55,7 +55,8 @@ public class MtpStorageManager { MtpObjectObserver(MtpObject object) { super(object.getPath().toString(), - MOVED_FROM | MOVED_TO | DELETE | CREATE | IN_ONLYDIR); + MOVED_FROM | MOVED_TO | DELETE | CREATE | IN_ONLYDIR + | CLOSE_WRITE); mObject = object; } @@ -85,6 +86,10 @@ public class MtpStorageManager { if (mObject.mObserver != null) mObject.mObserver.stopWatching(); mObject.mObserver = null; + } else if ((event & CLOSE_WRITE) != 0) { + if (sDebug) + Log.i(TAG, "inotify for " + mObject.getPath() + " CLOSE_WRITE: " + path); + handleChangedObject(mObject, path); } else { Log.w(TAG, "Got unrecognized event " + path + " " + event); } @@ -302,6 +307,11 @@ public class MtpStorageManager { * Called when an object is deleted. */ public abstract void sendObjectRemoved(int id); + + /** + * Called when an object info is changed. + */ + public abstract void sendObjectInfoChanged(int id); } private MtpNotifier mMtpNotifier; @@ -733,6 +743,25 @@ public class MtpStorageManager { Log.i(TAG, state + " transitioned to " + obj.getState() + " in op " + op); } + private synchronized void handleChangedObject(MtpObject parent, String path) { + MtpOperation op = MtpOperation.NONE; + MtpObject obj = parent.getChild(path); + if (obj != null) { + // Only handle files for size change notification event + if ((!obj.isDir()) && (obj.getSize() > 0)) + { + MtpObjectState state = obj.getState(); + op = obj.getOperation(); + MtpStorageManager.this.mMtpNotifier.sendObjectInfoChanged(obj.getId()); + if (sDebug) + Log.d(TAG, "sendObjectInfoChanged: id=" + obj.getId() + ",size=" + obj.getSize()); + } + } else { + if (sDebug) + Log.w(TAG, "object " + path + " null"); + } + } + /** * Block the caller until all events currently in the event queue have been * read and processed. Used for testing purposes. diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index c60590a748e0..39ff04ab2a0a 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -135,6 +135,18 @@ android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle } static void +android_mtp_MtpServer_send_object_info_changed(JNIEnv *env, jobject thiz, jint handle) +{ + Mutex::Autolock autoLock(sMutex); + + MtpServer* server = getMtpServer(env, thiz); + if (server) + server->sendObjectInfoChanged(handle); + else + ALOGE("server is null in send_object_info_changed"); +} + +static void android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) { Mutex::Autolock autoLock(sMutex); @@ -202,6 +214,7 @@ static const JNINativeMethod gMethods[] = { {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, + {"native_send_object_info_changed", "(I)V", (void *)android_mtp_MtpServer_send_object_info_changed}, {"native_send_device_property_changed", "(I)V", (void *)android_mtp_MtpServer_send_device_property_changed}, {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 8c9025b85860..693bd8b4b51c 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -824,21 +824,19 @@ static jobjectArray android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused, jint audioSession) { - effect_descriptor_t *descriptors = new effect_descriptor_t[AudioEffect::kMaxPreProcessing]; + auto descriptors = std::make_unique<effect_descriptor_t[]>(AudioEffect::kMaxPreProcessing); uint32_t numEffects = AudioEffect::kMaxPreProcessing; status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession, - descriptors, + descriptors.get(), &numEffects); if (status != NO_ERROR || numEffects == 0) { - delete[] descriptors; return NULL; } ALOGV("queryDefaultPreProcessing() got %d effects", numEffects); jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL); if (ret == NULL) { - delete[] descriptors; return ret; } @@ -875,7 +873,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ if (jdesc == NULL) { ALOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); env->DeleteLocalRef(ret); - return NULL;; + return NULL; } env->SetObjectArrayElement(ret, i, jdesc); diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java index d7833cc4e905..566d1c63fff3 100644 --- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java +++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java @@ -58,6 +58,7 @@ public class MtpStorageManagerTest { private ArrayList<Integer> objectsAdded; private ArrayList<Integer> objectsRemoved; + private ArrayList<Integer> objectsInfoChanged; private File mainStorageDir; private File secondaryStorageDir; @@ -73,15 +74,42 @@ public class MtpStorageManagerTest { Log.d(TAG, Thread.currentThread().getStackTrace()[3].getMethodName()); } + private static void logMethodValue(String szVar, int iValue) + { + Log.d(TAG, szVar + "=" + iValue + ": " + Thread.currentThread().getStackTrace()[3].getMethodName()); + } + + private static void vWriteNewFile(File newFile) { + try { + new FileOutputStream(newFile).write(new byte[] {0, 0, 0}); + } catch (IOException e) { + Assert.fail(); + } + } + private static File createNewFile(File parent) { - return createNewFile(parent, UUID.randomUUID().toString()); + return createNewFile(parent, "file-" + UUID.randomUUID().toString()); + } + + private static File createNewFileNonZero(File parent) { + return createNewFileNonZero(parent, "file-" + UUID.randomUUID().toString()); } private static File createNewFile(File parent, String name) { + return createNewFile(parent, name, false); + } + + private static File createNewFileNonZero(File parent, String name) { + return createNewFile(parent, name, true); + } + + private static File createNewFile(File parent, String name, boolean fgNonZero) { try { File ret = new File(parent, name); if (!ret.createNewFile()) throw new AssertionError("Failed to create file"); + if (fgNonZero) + vWriteNewFile(ret); // create non-zero size file return ret; } catch (IOException e) { throw new AssertionError(e.getMessage()); @@ -96,11 +124,12 @@ public class MtpStorageManagerTest { } private static File createNewDir(File parent) { - return createNewDir(parent, UUID.randomUUID().toString()); + return createNewDir(parent, "dir-" + UUID.randomUUID().toString()); } @Before public void before() { + FileUtils.deleteContentsAndDir(TEMP_DIR_FILE); Assert.assertTrue(TEMP_DIR_FILE.mkdir()); mainStorageDir = createNewDir(TEMP_DIR_FILE); secondaryStorageDir = createNewDir(TEMP_DIR_FILE); @@ -112,17 +141,26 @@ public class MtpStorageManagerTest { objectsAdded = new ArrayList<>(); objectsRemoved = new ArrayList<>(); + objectsInfoChanged = new ArrayList<>(); manager = new MtpStorageManager(new MtpStorageManager.MtpNotifier() { @Override public void sendObjectAdded(int id) { + Log.d(TAG, "sendObjectAdded " + id); objectsAdded.add(id); } @Override public void sendObjectRemoved(int id) { + Log.d(TAG, "sendObjectRemoved " + id); objectsRemoved.add(id); } + + @Override + public void sendObjectInfoChanged(int id) { + Log.d(TAG, "sendObjectInfoChanged: " + id); + objectsInfoChanged.add(id); + } }, null); mainMtpStorage = manager.addMtpStorage(mainStorage); @@ -469,11 +507,16 @@ public class MtpStorageManagerTest { mainMtpStorage.getStorageId()); Assert.assertEquals(stream.size(), 0); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), newFile.getPath()); + + logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size()); + if (objectsInfoChanged.size() > 0) + Assert.assertEquals(objectsAdded.get(0).intValue(), objectsInfoChanged.get(0).intValue()); + Assert.assertTrue(manager.checkConsistency()); } @@ -491,6 +534,7 @@ public class MtpStorageManagerTest { Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), newDir.getPath()); Assert.assertTrue(manager.getObject(objectsAdded.get(0)).isDir()); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -508,6 +552,7 @@ public class MtpStorageManagerTest { Assert.assertEquals(manager.getObject(objectsAdded.get(2)).getPath().toString(), newDir.getPath()); Assert.assertTrue(manager.getObject(objectsAdded.get(2)).isDir()); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -531,7 +576,7 @@ public class MtpStorageManagerTest { @SmallTest public void testObjectMoved() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); List<MtpStorageManager.MtpObject> stream = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()); Assert.assertEquals(stream.size(), 1); @@ -544,6 +589,7 @@ public class MtpStorageManagerTest { Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), toFile.getPath()); Assert.assertNull(manager.getObject(objectsRemoved.get(0))); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -561,7 +607,7 @@ public class MtpStorageManagerTest { "newFile", MtpConstants.FORMAT_UNDEFINED); Assert.assertEquals(id, 1); - File newFile = createNewFile(mainStorageDir, "newFile"); + File newFile = createNewFileNonZero(mainStorageDir, "newFile"); manager.flushEvents(); MtpStorageManager.MtpObject obj = manager.getObject(id); Assert.assertTrue(manager.endSendObject(obj, true)); @@ -586,11 +632,12 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endSendObject(obj, true)); Assert.assertEquals(obj.getPath().toString(), newFile.getPath()); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(obj.getFormat(), MtpConstants.FORMAT_ASSOCIATION); Assert.assertTrue(manager.checkConsistency()); // Check that new dir receives events - File newerFile = createNewFile(newFile); + File newerFile = createNewFileNonZero(newFile); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), @@ -609,7 +656,7 @@ public class MtpStorageManagerTest { MtpStorageManager.MtpObject obj = manager.getObject(id); Assert.assertTrue(manager.endSendObject(obj, true)); - File newFile = createNewFile(mainStorageDir, "newFile"); + File newFile = createNewFileNonZero(mainStorageDir, "newFile"); manager.flushEvents(); Assert.assertEquals(obj.getPath().toString(), newFile.getPath()); Assert.assertEquals(objectsAdded.size(), 0); @@ -632,11 +679,12 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertEquals(obj.getPath().toString(), newFile.getPath()); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(obj.getFormat(), MtpConstants.FORMAT_ASSOCIATION); Assert.assertTrue(manager.checkConsistency()); // Check that new dir receives events - File newerFile = createNewFile(newFile); + File newerFile = createNewFileNonZero(newFile); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), @@ -689,12 +737,13 @@ public class MtpStorageManagerTest { Assert.assertEquals(id, 1); MtpStorageManager.MtpObject obj = manager.getObject(id); - File newFile = createNewFile(mainStorageDir, "newFile"); + File newFile = createNewFileNonZero(mainStorageDir, "newFile"); Assert.assertTrue(newFile.delete()); manager.flushEvents(); Assert.assertTrue(manager.endSendObject(obj, false)); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -713,15 +762,21 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertTrue(manager.endSendObject(obj, false)); Assert.assertNotEquals(objectsAdded.get(0).intValue(), id); + logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size()); + if (objectsInfoChanged.size() > 0) + Assert.assertNotEquals(objectsInfoChanged.get(0).intValue(), id); Assert.assertNull(manager.getObject(id)); Assert.assertEquals(manager.getObject(objectsAdded.get(0)).getPath().toString(), newDir.getPath()); Assert.assertTrue(manager.checkConsistency()); // Expect events in new dir - createNewFile(newDir); + createNewFileNonZero(newDir); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 2); + logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size()); + if (objectsInfoChanged.size() == 1) + Assert.assertEquals(objectsAdded.get(1).intValue(), objectsInfoChanged.get(0).intValue()); Assert.assertTrue(manager.checkConsistency()); } @@ -764,13 +819,13 @@ public class MtpStorageManagerTest { public void testRemoveObjectDir() { logMethodName(); File newDir = createNewDir(mainStorageDir); - createNewFile(createNewDir(newDir)); + createNewFileNonZero(createNewDir(newDir)); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); manager.getObjects(obj.getId(), 0, mainMtpStorage.getStorageId()); Assert.assertTrue(manager.beginRemoveObject(obj)); - createNewFile(newDir); + createNewFileNonZero(newDir); Assert.assertTrue(FileUtils.deleteContentsAndDir(newDir)); manager.flushEvents(); Assert.assertTrue(manager.endRemoveObject(obj, true)); @@ -811,13 +866,16 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.beginRemoveObject(obj)); Assert.assertTrue(newFile.delete()); - createNewFile(mainStorageDir, newFile.getName()); + createNewFileNonZero(mainStorageDir, newFile.getName()); manager.flushEvents(); Assert.assertTrue(manager.endRemoveObject(obj, true)); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertNull(manager.getObject(id)); Assert.assertNotEquals(objectsAdded.get(0).intValue(), id); + logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size()); + if (objectsInfoChanged.size() > 0) + Assert.assertNotEquals(objectsInfoChanged.get(0).intValue(), objectsAdded.get(0).intValue()); Assert.assertTrue(manager.checkConsistency()); } @@ -850,6 +908,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRemoveObject(obj, false)); Assert.assertEquals(manager.getObject(obj.getId()), obj); Assert.assertEquals(objectsAdded.size(), 1); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -875,7 +934,7 @@ public class MtpStorageManagerTest { @SmallTest public void testCopyObjectSuccess() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File newDir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()) @@ -886,7 +945,7 @@ public class MtpStorageManagerTest { int id = manager.beginCopyObject(fileObj, dirObj); Assert.assertNotEquals(id, -1); - createNewFile(newDir, newFile.getName()); + createNewFileNonZero(newDir, newFile.getName()); manager.flushEvents(); MtpStorageManager.MtpObject obj = manager.getObject(id); Assert.assertTrue(manager.endCopyObject(obj, true)); @@ -900,9 +959,9 @@ public class MtpStorageManagerTest { logMethodName(); File newDirFrom = createNewDir(mainStorageDir); File newDirFrom1 = createNewDir(newDirFrom); - File newDirFrom2 = createNewFile(newDirFrom1); - File delayedFile = createNewFile(newDirFrom); - File deletedFile = createNewFile(newDirFrom); + File newDirFrom2 = createNewFileNonZero(newDirFrom1); + File delayedFile = createNewFileNonZero(newDirFrom); + File deletedFile = createNewFileNonZero(newDirFrom); File newDirTo = createNewDir(mainStorageDir); MtpStorageManager.MtpObject toObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -916,9 +975,9 @@ public class MtpStorageManagerTest { Assert.assertNotEquals(id, -1); File copiedDir = createNewDir(newDirTo, newDirFrom.getName()); File copiedDir1 = createNewDir(copiedDir, newDirFrom1.getName()); - createNewFile(copiedDir1, newDirFrom2.getName()); - createNewFile(copiedDir, "extraFile"); - File toDelete = createNewFile(copiedDir, deletedFile.getName()); + createNewFileNonZero(copiedDir1, newDirFrom2.getName()); + createNewFileNonZero(copiedDir, "extraFile"); + File toDelete = createNewFileNonZero(copiedDir, deletedFile.getName()); manager.flushEvents(); Assert.assertTrue(toDelete.delete()); manager.flushEvents(); @@ -927,13 +986,13 @@ public class MtpStorageManagerTest { Assert.assertEquals(objectsAdded.size(), 1); Assert.assertEquals(objectsRemoved.size(), 1); - createNewFile(copiedDir, delayedFile.getName()); + createNewFileNonZero(copiedDir, delayedFile.getName()); manager.flushEvents(); Assert.assertTrue(manager.checkConsistency()); // Expect events in the visited dir, but not the unvisited dir. - createNewFile(copiedDir); - createNewFile(copiedDir1); + createNewFileNonZero(copiedDir); + createNewFileNonZero(copiedDir1); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 2); Assert.assertEquals(objectsAdded.size(), 2); @@ -947,7 +1006,7 @@ public class MtpStorageManagerTest { @SmallTest public void testCopyObjectFailed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File newDir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -962,6 +1021,7 @@ public class MtpStorageManagerTest { MtpStorageManager.MtpObject obj = manager.getObject(id); Assert.assertTrue(manager.endCopyObject(obj, false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -969,7 +1029,7 @@ public class MtpStorageManagerTest { @SmallTest public void testCopyObjectFailedAdded() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File newDir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -989,7 +1049,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.checkConsistency()); // Expect events in new dir - createNewFile(addedDir); + createNewFileNonZero(addedDir); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 2); Assert.assertTrue(manager.checkConsistency()); @@ -999,7 +1059,7 @@ public class MtpStorageManagerTest { @SmallTest public void testCopyObjectFailedDeleted() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File newDir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1010,7 +1070,7 @@ public class MtpStorageManagerTest { int id = manager.beginCopyObject(fileObj, dirObj); Assert.assertNotEquals(id, -1); - Assert.assertTrue(createNewFile(newDir, newFile.getName()).delete()); + Assert.assertTrue(createNewFileNonZero(newDir, newFile.getName()).delete()); manager.flushEvents(); MtpStorageManager.MtpObject obj = manager.getObject(id); Assert.assertTrue(manager.endCopyObject(obj, false)); @@ -1022,7 +1082,7 @@ public class MtpStorageManagerTest { @SmallTest public void testRenameObjectSuccess() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginRenameObject(obj, "renamed")); @@ -1033,6 +1093,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(obj.getPath().toString(), renamed.getPath()); @@ -1054,6 +1115,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRenameObject(obj, newDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(obj.getPath().toString(), renamed.getPath()); @@ -1063,6 +1125,7 @@ public class MtpStorageManagerTest { createNewFile(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -1082,13 +1145,14 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRenameObject(obj, newDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(obj.getPath().toString(), renamed.getPath()); Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(renamed); + createNewFileNonZero(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1098,7 +1162,7 @@ public class MtpStorageManagerTest { @SmallTest public void testRenameObjectDelayed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginRenameObject(obj, "renamed")); @@ -1109,6 +1173,7 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(obj.getPath().toString(), renamed.getPath()); @@ -1131,13 +1196,14 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(obj.getPath().toString(), renamed.getPath()); Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(renamed); + createNewFileNonZero(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1147,7 +1213,7 @@ public class MtpStorageManagerTest { @SmallTest public void testRenameObjectFailed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginRenameObject(obj, "renamed")); @@ -1155,6 +1221,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertTrue(manager.checkConsistency()); @@ -1164,7 +1231,7 @@ public class MtpStorageManagerTest { @SmallTest public void testRenameObjectFailedOldRemoved() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginRenameObject(obj, "renamed")); @@ -1174,6 +1241,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1183,16 +1251,19 @@ public class MtpStorageManagerTest { @SmallTest public void testRenameObjectFailedNewAdded() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject obj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginRenameObject(obj, "renamed")); - createNewFile(mainStorageDir, "renamed"); + createNewFileNonZero(mainStorageDir, "renamed"); manager.flushEvents(); Assert.assertTrue(manager.endRenameObject(obj, newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 1); + logMethodValue("objectsInfoChanged.size", objectsInfoChanged.size()); + if (objectsInfoChanged.size() > 0) + Assert.assertNotEquals(objectsAdded.get(0).intValue(), objectsInfoChanged.get(0).intValue()); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertTrue(manager.checkConsistency()); @@ -1202,7 +1273,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectSuccess() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File dir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1220,6 +1291,7 @@ public class MtpStorageManagerTest { dirObj, newFile.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(fileObj.getPath().toString(), moved.getPath()); @@ -1248,6 +1320,7 @@ public class MtpStorageManagerTest { dirObj, movedDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath()); @@ -1257,6 +1330,7 @@ public class MtpStorageManagerTest { createNewFile(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -1283,13 +1357,14 @@ public class MtpStorageManagerTest { dirObj, movedDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath()); Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(renamed); + createNewFileNonZero(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1299,7 +1374,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectDelayed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File dir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1348,13 +1423,14 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(movedObj.getPath().toString(), renamed.getPath()); Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(renamed); + createNewFileNonZero(renamed); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1364,7 +1440,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectFailed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File dir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1379,6 +1455,7 @@ public class MtpStorageManagerTest { dirObj, newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertTrue(manager.checkConsistency()); @@ -1388,7 +1465,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectFailedOldRemoved() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File dir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1405,6 +1482,7 @@ public class MtpStorageManagerTest { dirObj, newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1414,7 +1492,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectFailedNewAdded() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); File dir = createNewDir(mainStorageDir); MtpStorageManager.MtpObject dirObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).stream() @@ -1424,7 +1502,7 @@ public class MtpStorageManagerTest { .filter(o -> !o.isDir()).findFirst().get(); Assert.assertTrue(manager.beginMoveObject(fileObj, dirObj)); - createNewFile(dir, newFile.getName()); + createNewFileNonZero(dir, newFile.getName()); manager.flushEvents(); Assert.assertTrue(manager.endMoveObject( manager.getStorageRoot(mainMtpStorage.getStorageId()), @@ -1440,14 +1518,14 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectXStorageSuccess() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginMoveObject(fileObj, manager.getStorageRoot(secondaryMtpStorage.getStorageId()))); Assert.assertTrue(newFile.delete()); - File moved = createNewFile(secondaryStorageDir, newFile.getName()); + File moved = createNewFileNonZero(secondaryStorageDir, newFile.getName()); manager.flushEvents(); Assert.assertTrue(manager.endMoveObject( manager.getStorageRoot(mainMtpStorage.getStorageId()), @@ -1481,6 +1559,7 @@ public class MtpStorageManagerTest { movedDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(), moved.getPath()); @@ -1491,6 +1570,7 @@ public class MtpStorageManagerTest { createNewFile(moved); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertTrue(manager.checkConsistency()); } @@ -1514,6 +1594,7 @@ public class MtpStorageManagerTest { movedDir.getName(), true)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(), moved.getPath()); @@ -1521,7 +1602,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(moved); + createNewFileNonZero(moved); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1531,7 +1612,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectXStorageDelayed() { logMethodName(); - File movedFile = createNewFile(mainStorageDir); + File movedFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject movedObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginMoveObject(movedObj, @@ -1543,7 +1624,7 @@ public class MtpStorageManagerTest { movedFile.getName(), true)); Assert.assertTrue(movedFile.delete()); - File moved = createNewFile(secondaryStorageDir, movedFile.getName()); + File moved = createNewFileNonZero(secondaryStorageDir, movedFile.getName()); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); @@ -1575,6 +1656,7 @@ public class MtpStorageManagerTest { manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertEquals(manager.getObject(movedObj.getId()).getPath().toString(), moved.getPath()); @@ -1582,7 +1664,7 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.checkConsistency()); // Expect events since the dir was visited - createNewFile(moved); + createNewFileNonZero(moved); manager.flushEvents(); Assert.assertEquals(objectsAdded.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1592,7 +1674,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectXStorageFailed() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginMoveObject(fileObj, @@ -1604,6 +1686,7 @@ public class MtpStorageManagerTest { newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 0); Assert.assertTrue(manager.checkConsistency()); @@ -1613,7 +1696,7 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectXStorageFailedOldRemoved() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginMoveObject(fileObj, @@ -1627,6 +1710,7 @@ public class MtpStorageManagerTest { newFile.getName(), false)); Assert.assertEquals(objectsAdded.size(), 0); + Assert.assertEquals(objectsInfoChanged.size(), 0); Assert.assertEquals(objectsRemoved.size(), 1); Assert.assertTrue(manager.checkConsistency()); @@ -1636,13 +1720,13 @@ public class MtpStorageManagerTest { @SmallTest public void testMoveObjectXStorageFailedNewAdded() { logMethodName(); - File newFile = createNewFile(mainStorageDir); + File newFile = createNewFileNonZero(mainStorageDir); MtpStorageManager.MtpObject fileObj = manager.getObjects(0xFFFFFFFF, 0, mainMtpStorage.getStorageId()).get(0); Assert.assertTrue(manager.beginMoveObject(fileObj, manager.getStorageRoot(secondaryMtpStorage.getStorageId()))); - createNewFile(secondaryStorageDir, newFile.getName()); + createNewFileNonZero(secondaryStorageDir, newFile.getName()); manager.flushEvents(); Assert.assertTrue(manager.endMoveObject( manager.getStorageRoot(mainMtpStorage.getStorageId()), @@ -1654,4 +1738,4 @@ public class MtpStorageManagerTest { Assert.assertTrue(manager.checkConsistency()); } -}
\ No newline at end of file +} diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml index 73d0764cdf96..ea4b09a52189 100644 --- a/packages/CarrierDefaultApp/res/values-kn/strings.xml +++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml @@ -8,7 +8,7 @@ <string name="portal_notification_detail" msgid="2295729385924660881">"%s ವೆಬ್ಸೈಟ್ಗೆ ಭೇಟಿ ನೀಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"ನಿಮಗೆ ಸೇವೆ ಒದಗಿಸುವವರನ್ನು ದಯವಿಟ್ಟು ಸಂಪರ್ಕಿಸಿ %s"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"ಮೊಬೈಲ್ ಡೇಟಾ ಸಂಪರ್ಕವಿಲ್ಲ"</string> - <string name="no_mobile_data_connection" msgid="544980465184147010">"%s ಮೂಲಕ ಡೇಟಾ ಅಥವಾ ರೋಮಿಂಗ್ ಪ್ಲ್ಯಾನ್ ಸೇರಿಸಿ"</string> + <string name="no_mobile_data_connection" msgid="544980465184147010">"%s ಮೂಲಕ ಡೇಟಾ ಅಥವಾ ರೋಮಿಂಗ್ ಪ್ಲಾನ್ ಸೇರಿಸಿ"</string> <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"ಮೊಬೈಲ್ ಡೇಟಾ ಸ್ಥಿತಿ"</string> <string name="action_bar_label" msgid="4290345990334377177">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"ನೀವು ಸೇರಬೇಕೆಂದಿರುವ ನೆಟ್ವರ್ಕ್, ಭದ್ರತೆ ಸಮಸ್ಯೆಗಳನ್ನು ಹೊಂದಿದೆ."</string> diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index f0f31fbded6f..3333e1592bfa 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -316,7 +316,7 @@ public class Assistant extends NotificationAssistantService { saveFile(); } } catch (Throwable e) { - Slog.e(TAG, "Error occurred processing removal", e); + Slog.e(TAG, "Error occurred processing removal of " + sbn, e); } } @@ -327,17 +327,21 @@ public class Assistant extends NotificationAssistantService { @Override public void onNotificationsSeen(List<String> keys) { - if (keys == null) { - return; - } + try { + if (keys == null) { + return; + } - for (String key : keys) { - NotificationEntry entry = mLiveNotifications.get(key); + for (String key : keys) { + NotificationEntry entry = mLiveNotifications.get(key); - if (entry != null) { - entry.setSeen(); - mAgingHelper.onNotificationSeen(entry); + if (entry != null) { + entry.setSeen(); + mAgingHelper.onNotificationSeen(entry); + } } + } catch (Throwable e) { + Slog.e(TAG, "Error occurred processing seen", e); } } diff --git a/packages/ExtServices/tests/AndroidTest.xml b/packages/ExtServices/tests/AndroidTest.xml new file mode 100644 index 000000000000..c3d32de4bfaf --- /dev/null +++ b/packages/ExtServices/tests/AndroidTest.xml @@ -0,0 +1,29 @@ +<?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. +--> +<configuration description="Runs Tests for ExtServices"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="ExtServicesUnitTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="ExtServicesUnitTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.ext.services.tests.unit" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration>
\ No newline at end of file diff --git a/packages/PackageInstaller/res/drawable/ic_file_download.xml b/packages/PackageInstaller/res/drawable/ic_file_download.xml index 7ea91f5baa2d..16c6080b46d5 100644 --- a/packages/PackageInstaller/res/drawable/ic_file_download.xml +++ b/packages/PackageInstaller/res/drawable/ic_file_download.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#000000" diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml index c8a80ac57c00..6b45a479836e 100644 --- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml +++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml @@ -14,5 +14,5 @@ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:alpha="0.24" android:color="?android:attr/colorBackground" /> + <item android:alpha="0.24" android:color="@android:color/black" /> </selector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml index 8dcfdbb8cf1e..5ef085b32dd6 100644 --- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml +++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml @@ -14,5 +14,5 @@ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:alpha="0.47" android:color="?android:attr/colorBackground" /> + <item android:alpha="0.47" android:color="@android:color/black" /> </selector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml index 34de5489a28b..81f63a48fb9a 100644 --- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml +++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml @@ -14,5 +14,5 @@ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:alpha="0.3" android:color="?android:attr/colorForeground" /> + <item android:alpha="0.3" android:color="@android:color/white" /> </selector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml index 15944c3a2a07..61f4e26cf00b 100644 --- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml +++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml @@ -14,5 +14,5 @@ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="?android:attr/colorForeground" /> + <item android:color="@android:color/white" /> </selector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 4bd79f960978..cd12f21cc1cc 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -22,7 +22,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्क के लिए स्कैन नहीं कर सकता"</string> <string name="wifi_security_none" msgid="7985461072596594400">"कोई नहीं"</string> - <string name="wifi_remembered" msgid="4955746899347821096">"सहेजा गया"</string> + <string name="wifi_remembered" msgid="4955746899347821096">"सेव किया गया"</string> <string name="wifi_disabled_generic" msgid="4259794910584943386">"अक्षम"</string> <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP कॉन्फ़िगरेशन की विफलता"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"खराब नेटवर्क होने के कारण कनेक्ट नहीं हुआ"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java index a91c45dd59af..a84222909072 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java @@ -57,9 +57,7 @@ public interface BluetoothCallback { default void onDeviceAdded(CachedBluetoothDevice cachedDevice) {} /** - * It will be called when a remote device that was - * found in the last discovery and is not found in the current discovery. - * It is listening {@link android.bluetooth.BluetoothDevice#ACTION_DISAPPEARED} + * It will be called when requiring to remove a remote device from CachedBluetoothDevice list * * @param cachedDevice the Bluetooth device. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 466d02bd3bcf..25e683100ee8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -81,7 +81,6 @@ public class BluetoothEventManager { addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true)); addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false)); addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler()); - addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler()); addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler()); addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler()); @@ -150,8 +149,7 @@ public class BluetoothEventManager { for (BluetoothDevice device : bondedDevices) { CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice == null) { - cachedDevice = mDeviceManager.addDevice(device); - dispatchDeviceAdded(cachedDevice); + mDeviceManager.addDevice(device); deviceAdded = true; } } @@ -276,7 +274,6 @@ public class BluetoothEventManager { public void onReceive(Context context, Intent intent, BluetoothDevice device) { short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE); - BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS); String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME); // TODO Pick up UUID. They should be available for 2.1 devices. // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1. @@ -287,8 +284,6 @@ public class BluetoothEventManager { + cachedDevice); } cachedDevice.setRssi(rssi); - cachedDevice.setBtClass(btClass); - cachedDevice.setNewName(name); cachedDevice.setJustDiscovered(true); } } @@ -303,24 +298,6 @@ public class BluetoothEventManager { } } - private class DeviceDisappearedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); - if (cachedDevice == null) { - Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device); - return; - } - if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceDeleted(cachedDevice); - } - } - } - } - } - private class NameChangedHandler implements Handler { public void onReceive(Context context, Intent intent, BluetoothDevice device) { @@ -339,18 +316,9 @@ public class BluetoothEventManager { BluetoothDevice.ERROR); CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice == null) { - Log.w(TAG, "CachedBluetoothDevice for device " + device + - " not found, calling readPairedDevices()."); - if (readPairedDevices()) { - cachedDevice = mDeviceManager.findDevice(device); - } - - if (cachedDevice == null) { - Log.w(TAG, "Got bonding state changed for " + device + - ", but we have no record of that device."); - cachedDevice = mDeviceManager.addDevice(device); - dispatchDeviceAdded(cachedDevice); - } + Log.w(TAG, "Got bonding state changed for " + device + + ", but we have no record of that device."); + cachedDevice = mDeviceManager.addDevice(device); } synchronized (mCallbacks) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index c511589bccca..68e1dfcfe959 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -51,13 +51,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private final BluetoothAdapter mLocalAdapter; private final LocalBluetoothProfileManager mProfileManager; private final BluetoothDevice mDevice; - //TODO: consider remove, BluetoothDevice.getName() is already cached - private String mName; private long mHiSyncId; // Need this since there is no method for getting RSSI private short mRssi; - //TODO: consider remove, BluetoothDevice.getBluetoothClass() is already cached - private BluetoothClass mBtClass; private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState; private final List<LocalBluetoothProfile> mProfiles = @@ -76,14 +72,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); - // Following constants indicate the user's choices of Phone book/message access settings - // User hasn't made any choice or settings app has wiped out the memory - public final static int ACCESS_UNKNOWN = 0; - // User has accepted the connection and let Settings app remember the decision - public final static int ACCESS_ALLOWED = 1; - // User has rejected the connection and let Settings app remember the decision - public final static int ACCESS_REJECTED = 2; - // How many times user should reject the connection to make the choice persist. private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2; @@ -299,7 +287,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } return; } - Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName); + Log.i(TAG, "Failed to connect " + profile.toString() + " to " + getName()); } private boolean ensurePaired() { @@ -376,8 +364,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // TODO: do any of these need to run async on a background thread? private void fillData() { - fetchName(); - fetchBtClass(); updateProfiles(); fetchActiveDevices(); migratePhonebookPermissionChoice(); @@ -400,21 +386,15 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return mDevice.getAddress(); } - public String getName() { - return mName; - } - /** - * Populate name from BluetoothDevice.ACTION_FOUND intent + * Get name from remote device + * @return {@link BluetoothDevice#getAliasName()} if + * {@link BluetoothDevice#getAliasName()} is not null otherwise return + * {@link BluetoothDevice#getAddress()} */ - void setNewName(String name) { - if (mName == null) { - mName = name; - if (mName == null || TextUtils.isEmpty(mName)) { - mName = mDevice.getAddress(); - } - dispatchAttributesChanged(); - } + public String getName() { + final String aliasName = mDevice.getAliasName(); + return TextUtils.isEmpty(aliasName) ? getAddress() : aliasName; } /** @@ -422,9 +402,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> * @param name new alias name to be set, should never be null */ public void setName(String name) { - // Prevent mName to be set to null if setName(null) is called - if (name != null && !TextUtils.equals(name, mName)) { - mName = name; + // Prevent getName() to be set to null if setName(null) is called + if (name != null && !TextUtils.equals(name, getName())) { mDevice.setAlias(name); dispatchAttributesChanged(); } @@ -461,19 +440,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } void refreshName() { - fetchName(); - dispatchAttributesChanged(); - } - - private void fetchName() { - mName = mDevice.getAliasName(); - - if (TextUtils.isEmpty(mName)) { - mName = mDevice.getAddress(); - if (BluetoothUtils.D) { - Log.d(TAG, "Device has no name (yet), use address: " + mName); - } + if (BluetoothUtils.D) { + Log.d(TAG, "Device name: " + getName()); } + dispatchAttributesChanged(); } /** @@ -606,13 +576,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return getBondState() == BluetoothDevice.BOND_BONDING; } - /** - * Fetches a new value for the cached BT class. - */ - private void fetchBtClass() { - mBtClass = mDevice.getBluetoothClass(); - } - private boolean updateProfiles() { ParcelUuid[] uuids = mDevice.getUuids(); if (uuids == null) return false; @@ -657,15 +620,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } /** - * Refreshes the UI for the BT class, including fetching the latest value - * for the class. - */ - void refreshBtClass() { - fetchBtClass(); - dispatchAttributesChanged(); - } - - /** * Refreshes the UI when framework alerts us of a UUID change. */ void onUuidChanged() { @@ -697,9 +651,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void onBondingStateChanged(int bondState) { if (bondState == BluetoothDevice.BOND_NONE) { mProfiles.clear(); - setPhonebookPermissionChoice(ACCESS_UNKNOWN); - setMessagePermissionChoice(ACCESS_UNKNOWN); - setSimPermissionChoice(ACCESS_UNKNOWN); + mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); + mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); + mDevice.setSimAccessPermission(BluetoothDevice.ACCESS_UNKNOWN); mMessageRejectionCount = 0; saveMessageRejectionCount(); } @@ -715,15 +669,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } } - void setBtClass(BluetoothClass btClass) { - if (btClass != null && mBtClass != btClass) { - mBtClass = btClass; - dispatchAttributesChanged(); - } - } - public BluetoothClass getBtClass() { - return mBtClass; + return mDevice.getBluetoothClass(); } public List<LocalBluetoothProfile> getProfiles() { @@ -757,7 +704,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } } - private void dispatchAttributesChanged() { + void dispatchAttributesChanged() { synchronized (mCallbacks) { for (Callback callback : mCallbacks) { callback.onDeviceAttributesChanged(); @@ -805,33 +752,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (comparison != 0) return comparison; // Fallback on name - return mName.compareTo(another.mName); + return getName().compareTo(another.getName()); } public interface Callback { void onDeviceAttributesChanged(); } - public int getPhonebookPermissionChoice() { - int permission = mDevice.getPhonebookAccessPermission(); - if (permission == BluetoothDevice.ACCESS_ALLOWED) { - return ACCESS_ALLOWED; - } else if (permission == BluetoothDevice.ACCESS_REJECTED) { - return ACCESS_REJECTED; - } - return ACCESS_UNKNOWN; - } - - public void setPhonebookPermissionChoice(int permissionChoice) { - int permission = BluetoothDevice.ACCESS_UNKNOWN; - if (permissionChoice == ACCESS_ALLOWED) { - permission = BluetoothDevice.ACCESS_ALLOWED; - } else if (permissionChoice == ACCESS_REJECTED) { - permission = BluetoothDevice.ACCESS_REJECTED; - } - mDevice.setPhonebookAccessPermission(permission); - } - // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth // app's shared preferences). private void migratePhonebookPermissionChoice() { @@ -842,10 +769,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) { - int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN); - if (oldPermission == ACCESS_ALLOWED) { + int oldPermission = + preferences.getInt(mDevice.getAddress(), BluetoothDevice.ACCESS_UNKNOWN); + if (oldPermission == BluetoothDevice.ACCESS_ALLOWED) { mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); - } else if (oldPermission == ACCESS_REJECTED) { + } else if (oldPermission == BluetoothDevice.ACCESS_REJECTED) { mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED); } } @@ -855,46 +783,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> editor.commit(); } - public int getMessagePermissionChoice() { - int permission = mDevice.getMessageAccessPermission(); - if (permission == BluetoothDevice.ACCESS_ALLOWED) { - return ACCESS_ALLOWED; - } else if (permission == BluetoothDevice.ACCESS_REJECTED) { - return ACCESS_REJECTED; - } - return ACCESS_UNKNOWN; - } - - public void setMessagePermissionChoice(int permissionChoice) { - int permission = BluetoothDevice.ACCESS_UNKNOWN; - if (permissionChoice == ACCESS_ALLOWED) { - permission = BluetoothDevice.ACCESS_ALLOWED; - } else if (permissionChoice == ACCESS_REJECTED) { - permission = BluetoothDevice.ACCESS_REJECTED; - } - mDevice.setMessageAccessPermission(permission); - } - - public int getSimPermissionChoice() { - int permission = mDevice.getSimAccessPermission(); - if (permission == BluetoothDevice.ACCESS_ALLOWED) { - return ACCESS_ALLOWED; - } else if (permission == BluetoothDevice.ACCESS_REJECTED) { - return ACCESS_REJECTED; - } - return ACCESS_UNKNOWN; - } - - void setSimPermissionChoice(int permissionChoice) { - int permission = BluetoothDevice.ACCESS_UNKNOWN; - if (permissionChoice == ACCESS_ALLOWED) { - permission = BluetoothDevice.ACCESS_ALLOWED; - } else if (permissionChoice == ACCESS_REJECTED) { - permission = BluetoothDevice.ACCESS_REJECTED; - } - mDevice.setSimAccessPermission(permission); - } - // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth // app's shared preferences). private void migrateMessagePermissionChoice() { @@ -905,10 +793,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) { - int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN); - if (oldPermission == ACCESS_ALLOWED) { + int oldPermission = + preferences.getInt(mDevice.getAddress(), BluetoothDevice.ACCESS_UNKNOWN); + if (oldPermission == BluetoothDevice.ACCESS_ALLOWED) { mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); - } else if (oldPermission == ACCESS_REJECTED) { + } else if (oldPermission == BluetoothDevice.ACCESS_REJECTED) { mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED); } } @@ -953,14 +842,14 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) { // The pairing dialog now warns of phone-book access for paired devices. // No separate prompt is displayed after pairing. - if (getPhonebookPermissionChoice() == CachedBluetoothDevice.ACCESS_UNKNOWN) { + if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) { if (mDevice.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE || mDevice.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) { - setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED); + mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED); } else { - setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED); + mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED); } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index f8543fc150e1..47bd853361ee 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -260,7 +260,7 @@ public class CachedBluetoothDeviceManager { public synchronized void onBtClassChanged(BluetoothDevice device) { CachedBluetoothDevice cachedDevice = findDevice(device); if (cachedDevice != null) { - cachedDevice.refreshBtClass(); + cachedDevice.dispatchAttributesChanged(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java index 6d60a09207a8..a6b24104fa90 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java @@ -58,17 +58,13 @@ public class Tile implements Parcelable { */ public ArrayList<UserHandle> userHandle = new ArrayList<>(); - /** - * The metaData from the activity that defines this tile. - */ - private final Bundle mMetaData; - private final String mActivityPackage; private final String mActivityName; private final Intent mIntent; + private ActivityInfo mActivityInfo; private CharSequence mSummaryOverride; - + private Bundle mMetaData; private String mCategory; public Tile(ActivityInfo activityInfo, String category) { @@ -234,6 +230,13 @@ public class Tile implements Parcelable { return summary; } + public void setMetaData(Bundle metaData) { + mMetaData = metaData; + } + + /** + * The metaData from the activity that defines this tile. + */ public Bundle getMetaData() { return mMetaData; } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index ffd6791725ed..67cfe6bfd18a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java @@ -20,10 +20,8 @@ import android.content.Context; import android.content.IContentProvider; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; @@ -43,7 +41,6 @@ import java.util.Map; public class TileUtils { - private static final boolean DEBUG = false; private static final boolean DEBUG_TIMING = false; private static final String LOG_TAG = "TileUtils"; @@ -70,7 +67,7 @@ public class TileUtils { /** * @See {@link #EXTRA_SETTINGS_ACTION}. */ - private static final String IA_SETTINGS_ACTION = "com.android.settings.action.IA_SETTINGS"; + public static final String IA_SETTINGS_ACTION = "com.android.settings.action.IA_SETTINGS"; /** * Same as #EXTRA_SETTINGS_ACTION but used for the platform Settings activities. @@ -205,12 +202,9 @@ public class TileUtils { /** * Build a list of DashboardCategory. - * - * @param extraAction additional intent filter action to be usetileutild to build the dashboard - * categories */ public static List<DashboardCategory> getCategories(Context context, - Map<Pair<String, String>, Tile> cache, String extraAction) { + Map<Pair<String, String>, Tile> cache) { final long startTime = System.currentTimeMillis(); boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) != 0; @@ -222,16 +216,13 @@ public class TileUtils { // Only add Settings for this user. getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true); getTilesForAction(context, user, OPERATOR_SETTINGS, cache, - OPERATOR_DEFAULT_CATEGORY, tiles, false, true); + OPERATOR_DEFAULT_CATEGORY, tiles, false); getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache, - MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true); + MANUFACTURER_DEFAULT_CATEGORY, tiles, false); } if (setup) { getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false); getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false); - if (extraAction != null) { - getTilesForAction(context, user, extraAction, cache, null, tiles, false); - } } } @@ -262,30 +253,15 @@ public class TileUtils { return categories; } - private static void getTilesForAction(Context context, - UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, - String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) { - getTilesForAction(context, user, action, addedCache, defaultCategory, outTiles, - requireSettings, requireSettings); - } - - private static void getTilesForAction(Context context, + @VisibleForTesting + static void getTilesForAction(Context context, UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, - String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings, - boolean usePriority) { - Intent intent = new Intent(action); + String defaultCategory, List<Tile> outTiles, boolean requireSettings) { + final Intent intent = new Intent(action); if (requireSettings) { intent.setPackage(SETTING_PKG); } - getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles, - usePriority); - } - - public static void getTilesForIntent( - Context context, UserHandle user, Intent intent, - Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, - boolean usePriority) { - PackageManager pm = context.getPackageManager(); + final PackageManager pm = context.getPackageManager(); List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, user.getIdentifier()); for (ResolveInfo resolved : results) { @@ -312,8 +288,9 @@ public class TileUtils { Tile tile = addedCache.get(key); if (tile == null) { tile = new Tile(activityInfo, categoryKey); - updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, pm); addedCache.put(key, tile); + } else { + tile.setMetaData(metaData); } if (!tile.userHandle.contains(user)) { @@ -325,34 +302,6 @@ public class TileUtils { } } - private static boolean updateTileData(Context context, Tile tile, - ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) { - if (applicationInfo.isSystemApp()) { - String summary = null; - - // Get the activity's meta-data - try { - Resources res = pm.getResourcesForApplication(applicationInfo.packageName); - Bundle metaData = activityInfo.metaData; - - if (res != null && metaData != null) { - if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { - if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) { - summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); - } else { - summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); - } - } - } - } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { - if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e); - } - return true; - } - - return false; - } - /** * Gets the icon package name and resource id from content provider. * 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 5e417c34a77a..c18db11a71a3 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 @@ -606,4 +606,35 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); } + + @Test + public void getName_aliasNameNotNull_returnAliasName() { + when(mDevice.getAliasName()).thenReturn(DEVICE_NAME); + + assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_NAME); + } + + @Test + public void getName_aliasNameIsNull_returnAddress() { + when(mDevice.getAliasName()).thenReturn(null); + + assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_ADDRESS); + } + + @Test + public void setName_setDeviceNameIsNotNull() { + final String name = "test name"; + when(mDevice.getAliasName()).thenReturn(DEVICE_NAME); + + mCachedDevice.setName(name); + + verify(mDevice).setAlias(name); + } + + @Test + public void setName_setDeviceNameIsNull() { + mCachedDevice.setName(null); + + verify(mDevice, never()).setAlias(any()); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 3eb273d55639..362ae4c84cbf 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.drawer; +import static com.android.settingslib.drawer.TileUtils.IA_SETTINGS_ACTION; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; @@ -24,9 +25,9 @@ import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMM import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeastOnce; @@ -52,6 +53,7 @@ import android.provider.Settings.Global; import android.util.ArrayMap; import android.util.Pair; +import com.android.settingslib.R; import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; @@ -98,15 +100,14 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldParseCategory() { final String testCategory = "category1"; - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); info.add(newInfo(true, testCategory)); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.size()).isEqualTo(1); @@ -116,60 +117,37 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldParseKeyHintForSystemApp() { String keyHint = "key"; - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, keyHint); info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, - null /* defaultCategory */, outTiles, false /* usePriority */); + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + null /* defaultCategory */, outTiles, false /* requiresSettings */); - assertThat(outTiles.size()).isEqualTo(1); + assertThat(outTiles).hasSize(1); assertThat(outTiles.get(0).getKey(mContext)).isEqualTo(keyHint); } @Test public void getTilesForIntent_shouldSkipNonSystemApp() { final String testCategory = "category1"; - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); info.add(newInfo(false, testCategory)); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, - null /* defaultCategory */, outTiles, false /* usePriority */); - - assertThat(outTiles.isEmpty()).isTrue(); - } - - @Test - public void getCategories_shouldHandleExtraIntentAction() { - final String testCategory = "category1"; - final String testAction = "action1"; - Map<Pair<String, String>, Tile> cache = new ArrayMap<>(); - List<ResolveInfo> info = new ArrayList<>(); - info.add(newInfo(true, testCategory)); - Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); - List<UserHandle> userHandleList = new ArrayList<>(); - userHandleList.add(UserHandle.CURRENT); - when(mUserManager.getUserProfiles()).thenReturn(userHandleList); - - when(mPackageManager.queryIntentActivitiesAsUser(argThat( - event -> testAction.equals(event.getAction())), anyInt(), anyInt())) - .thenReturn(info); + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, + addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */); - List<DashboardCategory> categoryList = TileUtils.getCategories(mContext, cache, testAction); - assertThat(categoryList.get(0).getTile(0).getCategory()).isEqualTo(testCategory); + assertThat(outTiles).isEmpty(); } @Test @@ -183,7 +161,7 @@ public class TileUtilsTest { userHandleList.add(new UserHandle(ActivityManager.getCurrentUser())); when(mUserManager.getUserProfiles()).thenReturn(userHandleList); - TileUtils.getCategories(mContext, cache, null /* action */); + TileUtils.getCategories(mContext, cache); verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser( intentCaptor.capture(), anyInt(), anyInt()); @@ -193,7 +171,6 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldReadMetadataTitleAsString() { - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); @@ -201,10 +178,10 @@ public class TileUtilsTest { URI_GET_SUMMARY, "my title", 0); info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.size()).isEqualTo(1); @@ -213,7 +190,6 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldReadMetadataTitleFromResource() { - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); @@ -221,13 +197,13 @@ public class TileUtilsTest { URI_GET_SUMMARY, null, 123); info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); when(mResources.getString(eq(123))) .thenReturn("my localized title"); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).getTitle(mContext)).isEqualTo("my localized title"); @@ -239,7 +215,6 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldNotTintIconIfInSettingsPackage() { - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); @@ -249,18 +224,50 @@ public class TileUtilsTest { resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings"; info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.get(0).isIconTintable(mContext)).isFalse(); } @Test + public void getTilesForIntent_tileAlreadyInCache_shouldUpdateMetaData() { + final Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); + final List<Tile> outTiles = new ArrayList<>(); + final List<ResolveInfo> info = new ArrayList<>(); + final ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, + URI_GET_SUMMARY, null, 123); + resolveInfo.activityInfo.packageName = "com.android.settings"; + resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings"; + info.add(resolveInfo); + + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) + .thenReturn(info); + + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + null /* defaultCategory */, outTiles, false /* usePriority */); + + assertThat(outTiles).hasSize(1); + final Bundle oldMetadata = outTiles.get(0).getMetaData(); + + resolveInfo.activityInfo.metaData = new Bundle(oldMetadata); + resolveInfo.activityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, + R.drawable.ic_bt_cellphone); + outTiles.clear(); + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + null /* defaultCategory */, outTiles, false /* usePriority */); + + assertThat(outTiles).hasSize(1); + final Bundle newMetaData = outTiles.get(0).getMetaData(); + assertThat(newMetaData).isNotSameAs(oldMetadata); + } + + + @Test public void getTilesForIntent_shouldMarkIconTintableIfMetadataSet() { - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); @@ -270,10 +277,10 @@ public class TileUtilsTest { .putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true); info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.get(0).isIconTintable(mContext)).isTrue(); @@ -281,7 +288,6 @@ public class TileUtilsTest { @Test public void getTilesForIntent_shouldProcessUriContentForSystemApp() { - Intent intent = new Intent(); Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); @@ -289,10 +295,10 @@ public class TileUtilsTest { URI_GET_SUMMARY); info.add(resolveInfo); - when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.size()).isEqualTo(1); diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index c9ba26804e89..091350334835 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -32,6 +32,7 @@ java_library { android_library { name: "SystemUI-core", srcs: [ + "src/**/*.kt", "src/**/*.java", "src/**/I*.aidl", ], @@ -73,6 +74,59 @@ android_library { ], } +android_library { + name: "SystemUI-tests", + manifest: "tests/AndroidManifest.xml", + resource_dirs: [ + "tests/res", + "res-keyguard", + "res", + ], + srcs: [ + "tests/src/**/*.kt", + "tests/src/**/*.java", + "src/**/*.kt", + "src/**/*.java", + "src/**/I*.aidl", + ], + static_libs: [ + "SystemUIPluginLib", + "SystemUISharedLib", + "SettingsLib", + "androidx.car_car", + "androidx.legacy_legacy-support-v4", + "androidx.recyclerview_recyclerview", + "androidx.preference_preference", + "androidx.appcompat_appcompat", + "androidx.mediarouter_mediarouter", + "androidx.palette_palette", + "androidx.legacy_legacy-preference-v14", + "androidx.leanback_leanback", + "androidx.slice_slice-core", + "androidx.slice_slice-view", + "androidx.slice_slice-builders", + "androidx.arch.core_core-runtime", + "androidx.lifecycle_lifecycle-extensions", + "SystemUI-tags", + "SystemUI-proto", + "metrics-helper-lib", + "android-support-test", + "mockito-target-inline-minus-junit4", + "testables", + "truth-prebuilt", + ], + libs: [ + "android.test.runner", + "telephony-common", + "android.car", + "android.test.base", + ], + aaptflags: [ + "--extra-packages", + "com.android.keyguard:com.android.systemui", + ], +} + android_app { name: "SystemUI", static_libs: [ diff --git a/packages/SystemUI/docs/kotlin-in-sysui.md b/packages/SystemUI/docs/kotlin-in-sysui.md new file mode 100644 index 000000000000..1bf24f63498b --- /dev/null +++ b/packages/SystemUI/docs/kotlin-in-sysui.md @@ -0,0 +1,22 @@ +# Kotlin in SystemUI + +Queue "it's happening" gif. + +Kotlin is probably going to be a bit of a wild west for a while, but please +try to follow these guidelines as much as possible. + + - No semi-colons: they are optional, we probably don't want them in the + future, so let's just not add them. + - No DSLs: sysui is complicated enough as is, let's not add more layers at + the moment. + - Only use extension functions for keeping complex code locality: Don't use + extension functions to add methods to android classes that you always wished + were there, instead add them directly to the class and save us the extension. + - inline, reified, and de-compisition can all be great things: just make sure + you know what they do and why you are using them. + +# Recommended reading + + - [Kotlin](https://kotlinlang.org/) + - [AndroidX-KTX](https://www.youtube.com/watch?v=st1XVfkDWqk) + - [Performance and Kotlin tricks](https://www.youtube.com/watch?v=6P20npkvcb8) diff --git a/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml b/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml deleted file mode 100644 index f91190b428d4..000000000000 --- a/packages/SystemUI/res/drawable-ldrtl/ic_sysbar_back_carmode.xml +++ /dev/null @@ -1,12 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="44dp" - android:height="44dp" - android:viewportWidth="44.0" - android:viewportHeight="44.0"> - <path - android:pathData="M35,21.94C35,22.78 34.49,23.58 33.64,24.05L12.44,36.13C11.43,36.7 10.58,36.51 10.11,36.25C9.08,35.67 9,34.56 9,34.09L9,9.91C9,9.35 9.08,8.31 10.09,7.75C10.54,7.49 11.34,7.31 12.33,7.86L33.74,19.95C34.51,20.39 35,21.13 35,21.94L35,21.94ZM12.5,32L30.5,21.96L12.5,12L12.5,32Z" - android:strokeColor="#00000000" - android:fillType="evenOdd" - android:fillColor="#F8F9FA" - android:strokeWidth="1"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml deleted file mode 100644 index 542ba9b2a0d5..000000000000 --- a/packages/SystemUI/res/drawable/ic_sysbar_back_ime_carmode.xml +++ /dev/null @@ -1,12 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="44dp" - android:height="44dp" - android:viewportWidth="44.0" - android:viewportHeight="44.0"> - <path - android:pathData="M22.06,35C21.22,35 20.42,34.49 19.95,33.64L7.87,12.44C7.3,11.43 7.49,10.58 7.75,10.11C8.33,9.08 9.44,9 9.91,9L34.09,9C34.65,9 35.69,9.08 36.25,10.09C36.51,10.54 36.69,11.34 36.14,12.33L24.05,33.74C23.61,34.51 22.87,35 22.06,35L22.06,35ZM12,12.5L22.04,30.5L32,12.5L12,12.5Z" - android:strokeColor="#00000000" - android:fillType="evenOdd" - android:fillColor="#F8F9FA" - android:strokeWidth="1"/> -</vector> diff --git a/packages/SystemUI/res/layout/qs_customize_divider.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml index 51febc78e23e..6fcfa8d27a7a 100644 --- a/packages/SystemUI/res/layout/qs_customize_divider.xml +++ b/packages/SystemUI/res/layout/qs_customize_divider.xml @@ -23,6 +23,6 @@ android:gravity="center" android:paddingTop="20dp" android:paddingBottom="13dp" - android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textAppearance="@style/TextAppearance.QSEdit.Headers" android:textColor="?android:attr/colorAccent" android:text="@string/drag_to_add_tiles" /> diff --git a/packages/SystemUI/res/layout/qs_customize_header.xml b/packages/SystemUI/res/layout/qs_customize_header.xml new file mode 100644 index 000000000000..093f9719c0de --- /dev/null +++ b/packages/SystemUI/res/layout/qs_customize_header.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. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:minHeight="28dp" + android:textAppearance="@style/TextAppearance.QSEdit.Headers" + android:textColor="?android:attr/colorAccent" + android:text="@string/drag_to_rearrange_tiles" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml index 4ce6ef6ed31d..bb67c547c36e 100644 --- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml +++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml @@ -43,7 +43,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:paddingTop="28dp" android:paddingLeft="@dimen/qs_tile_layout_margin_side" android:paddingRight="@dimen/qs_tile_layout_margin_side" android:paddingBottom="28dp" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 412e89ad169a..7e35f5f70575 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -952,6 +952,7 @@ <dimen name="nav_content_padding">0dp</dimen> <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen> <dimen name="nav_quick_scrub_track_thickness">10dp</dimen> + <dimen name="nav_home_back_gesture_drag_limit">60dp</dimen> <!-- Navigation bar shadow params. --> <dimen name="nav_key_button_shadow_offset_x">0dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 9a64c604ad0c..36f97cd64642 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -69,13 +69,13 @@ <!-- A message that appears when the battery remaining estimate is low in a dialog. This is appended to the subtitle of the low battery alert. "percentage" is the percentage of battery remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]--> - <string name="battery_low_percent_format_hybrid"><xliff:g id="percentage">%s</xliff:g> remaining, about <xliff:g id="time">%s</xliff:g> left based on your usage</string> + <string name="battery_low_percent_format_hybrid"><xliff:g id="percentage">%1$s</xliff:g> remaining, about <xliff:g id="time">%2$s</xliff:g> left based on your usage</string> <!-- A message that appears when the battery remaining estimate is low in a dialog and insufficient data was present to say it is customized to the user. This is appended to the subtitle of the low battery alert. "percentage" is the percentage of battery remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]--> - <string name="battery_low_percent_format_hybrid_short"><xliff:g id="percentage">%s</xliff:g> remaining, about <xliff:g id="time">%s</xliff:g> left</string> + <string name="battery_low_percent_format_hybrid_short"><xliff:g id="percentage">%1$s</xliff:g> remaining, about <xliff:g id="time">%2$s</xliff:g> left</string> <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]--> <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery Saver is on.</string> @@ -624,7 +624,7 @@ <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] --> <string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string> <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "New message, +3" [CHAR LIMIT=7] --> - <string name="notification_group_overflow_indicator_ambient"><xliff:g id="notification_title" example="New message">%s</xliff:g>, +<xliff:g id="overflow" example="+3">%s</xliff:g></string> + <string name="notification_group_overflow_indicator_ambient"><xliff:g id="notification_title" example="New message">%1$s</xliff:g>, +<xliff:g id="overflow" example="+3">%2$s</xliff:g></string> <!-- Content description describing how many more notifications are in a group [CHAR LIMIT=NONE] --> <plurals name="notification_group_overflow_description"> @@ -956,13 +956,13 @@ <string name="interruption_level_alarms_twoline">Alarms\nonly</string> <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=50]--> - <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string> <!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=50]--> - <string name="keyguard_indication_charging_time_fast"><xliff:g id="percentage">%2$s</xliff:g> • Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <string name="keyguard_indication_charging_time_fast"><xliff:g id="percentage">%2$s</xliff:g> • Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string> <!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=50]--> - <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string> <!-- Related to user switcher --><skip/> @@ -1038,6 +1038,15 @@ <!-- Message for add user confirmation dialog - short version. [CHAR LIMIT=none] --> <string name="user_add_user_message_short" msgid="1511354412249044381">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string> + <!-- Title for the dialog that lets users know that the maximum allowed number of users on the device has been reached. [CHAR LIMIT=35]--> + <string name="user_limit_reached_title">User limit reached</string> + + <!-- Message that tells people what's the maximum number of uses allowed on the device. [CHAR_LIMIT=NONE]--> + <plurals name="user_limit_reached_message"> + <item quantity="one">Only one user can be created.</item> + <item quantity="other">You can add up to <xliff:g id="count" example="3">%d</xliff:g> users.</item> + </plurals> + <!-- Title of the confirmation dialog for deleting a user [CHAR LIMIT=NONE] --> <string name="user_remove_user_title">Remove user?</string> @@ -1869,6 +1878,9 @@ <!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] --> <string name="drag_to_add_tiles">Hold and drag to add tiles</string> + <!-- Label for header of customize QS [CHAR LIMIT=60] --> + <string name="drag_to_rearrange_tiles">Hold and drag to rearrange tiles</string> + <!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] --> <string name="drag_to_remove_tiles">Drag here to remove</string> @@ -2133,7 +2145,7 @@ <string name="mobile_data">Mobile data</string> <!-- Quick settings tile secondary label format combining roaming with the mobile data type. [CHAR LIMIT=NONE] --> - <string name="mobile_data_text_format"><xliff:g name="roaming_status" example="Roaming">%s</xliff:g> \u2014 <xliff:g name="mobile_data_type" example="LTE">%s</xliff:g></string> + <string name="mobile_data_text_format"><xliff:g name="roaming_status" example="Roaming">%1$s</xliff:g> \u2014 <xliff:g name="mobile_data_type" example="LTE">%2$s</xliff:g></string> <!-- Label for when wifi is off in QS detail panel [CHAR LIMIT=NONE] --> <string name="wifi_is_off">Wi-Fi is off</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index c0b50ea3c67b..8442dd13a85b 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -321,12 +321,15 @@ <item name="*android:isLightTheme">false</item> </style> - <style name="Theme.SystemUI.Light" parent="@*android:style/Theme.DeviceDefault.QuickSettings"> + <style name="Theme.SystemUI.Light"> <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item> <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item> <item name="android:colorError">@*android:color/error_color_material_light</item> <item name="android:colorControlHighlight">#40000000</item> <item name="passwordStyle">@style/PasswordTheme.Light</item> + + <!-- Needed for MediaRoute chooser dialog --> + <item name="*android:isLightTheme">true</item> </style> <style name="LockPatternStyle"> @@ -495,6 +498,11 @@ parent="@*android:style/TextAppearance.Material.Notification.Info"> </style> + <style name="TextAppearance.QSEdit.Headers" + parent="@*android:style/TextAppearance.Material.Body2"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + </style> + <style name="edit_theme" parent="qs_theme"> <item name="android:colorBackground">?android:attr/colorSecondary</item> </style> diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 0fb12009e2cb..eb71698136fc 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -20,6 +20,9 @@ android_library { "src/**/I*.aidl", ], + // Enforce that the library is build agains java 7 so that there are + // no compatibility issues with launcher + java_version: "1.7", } android_app { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index ebfadd881c19..1c46f12f02cd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -17,7 +17,6 @@ package com.android.systemui.shared.recents; import android.graphics.Rect; -import com.android.systemui.shared.system.GraphicBufferCompat; /** * Temporary callbacks into SystemUI. @@ -26,9 +25,10 @@ interface ISystemUiProxy { /** * Proxies SurfaceControl.screenshotToBuffer(). + * @Removed + * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, + * int maxLayer, boolean useIdentityTransform, int rotation) = 0; */ - GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, - int maxLayer, boolean useIdentityTransform, int rotation) = 0; /** * Begins screen pinning on the provided {@param taskId}. diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java index a0e7752e13fa..19e8673fba89 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java @@ -110,11 +110,19 @@ class BackgroundTaskLoader implements Runnable { synchronized(mLoadQueue) { try { mWaitingOnLoadQueue = true; - mMainThreadHandler.post( - () -> mOnIdleChangedListener.onIdleChanged(true)); + mMainThreadHandler.post(new Runnable() { + @Override + public void run() { + mOnIdleChangedListener.onIdleChanged(true); + } + }); mLoadQueue.wait(); - mMainThreadHandler.post( - () -> mOnIdleChangedListener.onIdleChanged(false)); + mMainThreadHandler.post(new Runnable() { + @Override + public void run() { + mOnIdleChangedListener.onIdleChanged(false); + } + }); mWaitingOnLoadQueue = false; } catch (InterruptedException ie) { ie.printStackTrace(); @@ -142,8 +150,12 @@ class BackgroundTaskLoader implements Runnable { if (!mCancelled) { // Notify that the task data has changed - mMainThreadHandler.post( - () -> t.notifyTaskDataLoaded(thumbnailData, icon)); + mMainThreadHandler.post(new Runnable() { + @Override + public void run() { + t.notifyTaskDataLoaded(thumbnailData, icon); + } + }); } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java index 24ba99840165..852463ffc188 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java @@ -34,7 +34,8 @@ import java.util.ArrayList; /** * Loader class that loads full-resolution thumbnails when appropriate. */ -public class HighResThumbnailLoader implements TaskCallbacks { +public class HighResThumbnailLoader implements + TaskCallbacks, BackgroundTaskLoader.OnIdleChangedListener { private final ActivityManagerWrapper mActivityManager; @@ -80,6 +81,11 @@ public class HighResThumbnailLoader implements TaskCallbacks { updateLoading(); } + @Override + public void onIdleChanged(boolean idle) { + setTaskLoadQueueIdle(idle); + } + /** * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not * starting this queue until the other queue is idling. @@ -220,15 +226,18 @@ public class HighResThumbnailLoader implements TaskCallbacks { } } - private void loadTask(Task t) { - ThumbnailData thumbnail = mActivityManager.getTaskThumbnail(t.key.id, + private void loadTask(final Task t) { + final ThumbnailData thumbnail = mActivityManager.getTaskThumbnail(t.key.id, false /* reducedResolution */); - mMainThreadHandler.post(() -> { - synchronized (mLoadQueue) { - mLoadingTasks.remove(t); - } - if (mVisibleTasks.contains(t)) { - t.notifyTaskDataLoaded(thumbnail, t.icon); + mMainThreadHandler.post(new Runnable() { + @Override + public void run() { + synchronized (mLoadQueue) { + mLoadingTasks.remove(t); + } + if (mVisibleTasks.contains(t)) { + t.notifyTaskDataLoaded(thumbnail, t.icon); + } } }); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java index ab2e277ecfd6..996c837ba121 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java @@ -110,8 +110,7 @@ public class RecentsTaskLoader { mActivityInfoCache = new LruCache<>(numRecentTasks); mIconLoader = createNewIconLoader(context, mIconCache, mActivityInfoCache); - mLoader = new BackgroundTaskLoader(mLoadQueue, mIconLoader, - mHighResThumbnailLoader::setTaskLoadQueueIdle); + mLoader = new BackgroundTaskLoader(mLoadQueue, mIconLoader, mHighResThumbnailLoader); } protected IconLoader createNewIconLoader(Context context,TaskKeyLruCache<Drawable> iconCache, diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java index a36939769477..c731ac9b8886 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java @@ -19,6 +19,7 @@ package com.android.systemui.shared.recents.model; import android.content.ComponentName; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.SparseArray; import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.utilities.AnimationProps; @@ -67,7 +68,12 @@ public class TaskStack { public TaskStack() { // Ensure that we only show stack tasks - mStackTaskList.setFilter((taskIdMap, t, index) -> t.isStackTask); + mStackTaskList.setFilter(new TaskFilter() { + @Override + public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) { + return t.isStackTask; + } + }); } /** Sets the callbacks for this task stack. */ 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 0ded9631cb3d..b04d04717be5 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 @@ -201,8 +201,8 @@ public class ActivityManagerWrapper { /** * Starts the recents activity. The caller should manage the thread on which this is called. */ - public void startRecentsActivity(Intent intent, AssistDataReceiver assistDataReceiver, - RecentsAnimationListener animationHandler, Consumer<Boolean> resultCallback, + public void startRecentsActivity(Intent intent, final AssistDataReceiver assistDataReceiver, + final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback, Handler resultCallbackHandler) { try { IAssistDataReceiver receiver = null; @@ -284,9 +284,9 @@ public class ActivityManagerWrapper { * @param resultCallback The result success callback * @param resultCallbackHandler The handler to receive the result callback */ - public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options, - int windowingMode, int activityType, Consumer<Boolean> resultCallback, - Handler resultCallbackHandler) { + public void startActivityFromRecentsAsync(final Task.TaskKey taskKey, ActivityOptions options, + int windowingMode, int activityType, final Consumer<Boolean> resultCallback, + final Handler resultCallbackHandler) { if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // We show non-visible docked tasks in Recents, but we always want to launch // them in the fullscreen stack. @@ -364,7 +364,7 @@ public class ActivityManagerWrapper { /** * Requests that the system close any open system windows (including other SystemUI). */ - public void closeSystemWindows(String reason) { + public void closeSystemWindows(final String reason) { mBackgroundExecutor.submit(new Runnable() { @Override public void run() { @@ -380,7 +380,7 @@ public class ActivityManagerWrapper { /** * Removes a task by id. */ - public void removeTask(int taskId) { + public void removeTask(final int taskId) { mBackgroundExecutor.submit(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java deleted file mode 100644 index 66b8fed1a48f..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java +++ /dev/null @@ -1,64 +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 com.android.systemui.shared.system; - -import android.graphics.Bitmap; -import android.graphics.GraphicBuffer; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Wraps the internal graphic buffer. - */ -public class GraphicBufferCompat implements Parcelable { - - private GraphicBuffer mBuffer; - - public GraphicBufferCompat(GraphicBuffer buffer) { - mBuffer = buffer; - } - - public GraphicBufferCompat(Parcel in) { - mBuffer = GraphicBuffer.CREATOR.createFromParcel(in); - } - - public Bitmap toBitmap() { - return mBuffer != null - ? Bitmap.createHardwareBitmap(mBuffer) - : null; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - mBuffer.writeToParcel(dest, flags); - } - - public static final Parcelable.Creator<GraphicBufferCompat> CREATOR - = new Parcelable.Creator<GraphicBufferCompat>() { - public GraphicBufferCompat createFromParcel(Parcel in) { - return new GraphicBufferCompat(in); - } - - public GraphicBufferCompat[] newArray(int size) { - return new GraphicBufferCompat[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index 625b1de74290..61be076ac48a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -41,11 +41,11 @@ public class RemoteAnimationAdapterCompat { } private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( - RemoteAnimationRunnerCompat remoteAnimationAdapter) { + final RemoteAnimationRunnerCompat remoteAnimationAdapter) { return new IRemoteAnimationRunner.Stub() { @Override public void onAnimationStart(RemoteAnimationTarget[] apps, - IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + final IRemoteAnimationFinishedCallback finishedCallback) { final RemoteAnimationTargetCompat[] appsCompat = RemoteAnimationTargetCompat.wrap(apps); final Runnable animationFinishedCallback = new Runnable() { @@ -63,7 +63,7 @@ public class RemoteAnimationAdapterCompat { } @Override - public void onAnimationCancelled() throws RemoteException { + public void onAnimationCancelled() { remoteAnimationAdapter.onAnimationCancelled(); } }; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java index 217e0aaac709..dc4eb3b71faa 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java @@ -21,6 +21,7 @@ import android.graphics.Rect; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewRootImpl; @@ -47,11 +48,13 @@ public class SyncRtSurfaceTransactionApplier { * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into * this method to avoid synchronization issues. */ - public void scheduleApply(SurfaceParams... params) { + public void scheduleApply(final SurfaceParams... params) { if (mTargetViewRootImpl == null) { return; } - mTargetViewRootImpl.registerRtFrameCallback(frame -> { + mTargetViewRootImpl.registerRtFrameCallback(new ThreadedRenderer.FrameDrawingCallback() { + @Override + public void onFrameDraw(long frame) { if (mTargetSurface == null || !mTargetSurface.isValid()) { return; } @@ -64,6 +67,7 @@ public class SyncRtSurfaceTransactionApplier { } t.setEarlyWakeup(); t.apply(); + } }); // Make sure a frame gets scheduled. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 9bf781678962..5ffdc7b221f3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -145,6 +145,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit mLockPatternView = findViewById(R.id.lockPatternView); mLockPatternView.setSaveEnabled(false); mLockPatternView.setOnPatternListener(new UnlockPatternListener()); + mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( + KeyguardUpdateMonitor.getCurrentUser())); // vibrate mode will be the same for the life of this screen mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index d5383b975211..f6fec5456ed8 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -82,7 +82,6 @@ public class BatteryMeterView extends LinearLayout implements private int mLightModeBackgroundColor; private int mLightModeFillColor; - private float mDarkIntensity; private int mUser; /** @@ -321,8 +320,6 @@ public class BatteryMeterView extends LinearLayout implements @Override public void onDarkChanged(Rect area, float darkIntensity, int tint) { - mDarkIntensity = darkIntensity; - float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0; mNonAdaptedForegroundColor = getColorForDarkIntensity( intensity, mLightModeFillColor, mDarkModeFillColor); @@ -342,14 +339,6 @@ public class BatteryMeterView extends LinearLayout implements } } - public void setFillColor(int color) { - if (mLightModeFillColor == color) { - return; - } - mLightModeFillColor = color; - onDarkChanged(new Rect(), mDarkIntensity, DarkIconDispatcher.DEFAULT_ICON_TINT); - } - private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) { return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor); } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 86e0e1f9a734..2dd54aa5715c 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -23,6 +23,7 @@ import android.os.Looper; import android.os.Process; import android.os.ServiceManager; import android.util.ArrayMap; +import android.util.DisplayMetrics; import android.view.IWindowManager; import android.view.WindowManagerGlobal; @@ -51,11 +52,12 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; -import com.android.systemui.statusbar.phone.StatusBarWindowManager; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.BatteryController; @@ -258,8 +260,8 @@ public class Dependency extends SystemUI { mProviders.put(TunerService.class, () -> new TunerServiceImpl(mContext)); - mProviders.put(StatusBarWindowManager.class, () -> - new StatusBarWindowManager(mContext)); + mProviders.put(StatusBarWindowController.class, () -> + new StatusBarWindowController(mContext)); mProviders.put(DarkIconDispatcher.class, () -> new DarkIconDispatcherImpl(mContext)); @@ -328,6 +330,12 @@ public class Dependency extends SystemUI { mProviders.put(IStatusBarService.class, () -> IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE))); + // Single instance of DisplayMetrics, gets updated by StatusBar, but can be used + // anywhere it is needed. + mProviders.put(DisplayMetrics.class, () -> new DisplayMetrics()); + + mProviders.put(LockscreenGestureLogger.class, () -> new LockscreenGestureLogger()); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 50d862dee29c..acc7b49d9c35 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -30,6 +30,7 @@ import android.service.wallpaper.WallpaperService; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; +import android.view.DisplayListCanvas; import android.view.Surface; import android.view.SurfaceHolder; import android.view.WindowManager; @@ -273,7 +274,9 @@ public class ImageWallpaper extends WallpaperService { // Sometimes a wallpaper is not large enough to cover the screen in one dimension. // Call updateSurfaceSize -- it will only actually do the update if the dimensions // should change - if (newRotation != mLastRotation) { + if (newRotation != mLastRotation + || mDisplayWidthAtLastSurfaceSizeUpdate != displayInfo.logicalWidth + || mDisplayHeightAtLastSurfaceSizeUpdate != displayInfo.logicalHeight) { // Update surface size (if necessary) if (!updateSurfaceSize(getSurfaceHolder(), displayInfo, true /* forDraw */)) { return; // had to reload wallpaper, will retry later @@ -366,7 +369,12 @@ public class ImageWallpaper extends WallpaperService { protected Bitmap doInBackground(Void... params) { Throwable exception; try { - return mWallpaperManager.getBitmap(true /* hardware */); + Bitmap wallpaper = mWallpaperManager.getBitmap(true /* hardware */); + if (wallpaper != null + && wallpaper.getByteCount() > DisplayListCanvas.MAX_BITMAP_SIZE) { + throw new RuntimeException("Wallpaper is too large to draw!"); + } + return wallpaper; } catch (RuntimeException | OutOfMemoryError e) { exception = e; } diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 0864ff03a9db..cafdc10beefa 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -32,7 +32,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import android.view.SurfaceControl; import com.android.systemui.OverviewProxyService.OverviewProxyListener; import com.android.systemui.recents.events.EventBus; @@ -41,7 +40,6 @@ 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; -import com.android.systemui.shared.system.GraphicBufferCompat; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.CallbackController; @@ -70,6 +68,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private static final long BACKOFF_MILLIS = 1000; private static final long DEFERRED_CALLBACK_MILLIS = 5000; + // Max backoff caps at 5 mins + private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; + // Default interaction flags if swipe up is disabled before connecting to launcher private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP | FLAG_SHOW_OVERVIEW_BUTTON; @@ -88,23 +89,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private @InteractionType int mInteractionFlags; private boolean mIsEnabled; private int mCurrentBoundedUserId = -1; + private float mBackButtonAlpha; private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { - public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer, - int maxLayer, boolean useIdentityTransform, int rotation) { - if (!verifyCaller("screenshot")) { - return null; - } - long token = Binder.clearCallingIdentity(); - try { - return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width, - height, minLayer, maxLayer, useIdentityTransform, rotation)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - public void startScreenPinning(int taskId) { if (!verifyCaller("startScreenPinning")) { return; @@ -193,6 +181,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } long token = Binder.clearCallingIdentity(); try { + mBackButtonAlpha = alpha; mHandler.post(() -> { notifyBackButtonAlphaChanged(alpha, animate); }); @@ -215,7 +204,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final Runnable mDeferredConnectionCallback = () -> { Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service " + "timed out, trying again"); - internalConnectToCurrentUser(); + retryConnectionWithBackoff(); }; private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() { @@ -260,14 +249,14 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public void onNullBinding(ComponentName name) { Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting"); mCurrentBoundedUserId = -1; - internalConnectToCurrentUser(); + retryConnectionWithBackoff(); } @Override public void onBindingDied(ComponentName name) { Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting"); mCurrentBoundedUserId = -1; - internalConnectToCurrentUser(); + retryConnectionWithBackoff(); } @Override @@ -322,6 +311,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + public float getBackButtonAlpha() { + return mBackButtonAlpha; + } + public void startConnectionToCurrentUser() { if (mHandler.getLooper() != Looper.myLooper()) { mHandler.post(mConnectionRunnable); @@ -357,12 +350,20 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS); } else { // Retry after exponential backoff timeout - final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts); - mHandler.postDelayed(mConnectionRunnable, timeoutMs); - mConnectionBackoffAttempts++; - Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts - + " will try again in " + timeoutMs + "ms"); + retryConnectionWithBackoff(); + } + } + + private void retryConnectionWithBackoff() { + if (mHandler.hasCallbacks(mConnectionRunnable)) { + return; } + final long timeoutMs = (long) Math.min( + Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS); + mHandler.postDelayed(mConnectionRunnable, timeoutMs); + mConnectionBackoffAttempts++; + Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts + + " will try again in " + timeoutMs + "ms"); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 9bbcfbcd07dd..044cc5cab20c 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -94,9 +94,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { private DisplayManager mDisplayManager; private DisplayManager.DisplayListener mDisplayListener; - private int mRoundedDefault; - private int mRoundedDefaultTop; - private int mRoundedDefaultBottom; + @VisibleForTesting protected int mRoundedDefault; + @VisibleForTesting protected int mRoundedDefaultTop; + @VisibleForTesting protected int mRoundedDefaultBottom; private View mOverlay; private View mBottomOverlay; private float mDensity; @@ -125,12 +125,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private void startOnScreenDecorationsThread() { mRotation = RotationUtils.getExactRotation(mContext); mWindowManager = mContext.getSystemService(WindowManager.class); - mRoundedDefault = mContext.getResources().getDimensionPixelSize( - R.dimen.rounded_corner_radius); - mRoundedDefaultTop = mContext.getResources().getDimensionPixelSize( - R.dimen.rounded_corner_radius_top); - mRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize( - R.dimen.rounded_corner_radius_bottom); + updateRoundedCornerRadii(); if (hasRoundedCorners() || shouldDrawCutout()) { setupDecorations(); } @@ -277,6 +272,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { int oldRotation = mRotation; mPendingRotationChange = false; updateOrientation(); + updateRoundedCornerRadii(); if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation); if (shouldDrawCutout() && mOverlay == null) { setupDecorations(); @@ -309,6 +305,26 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + private void updateRoundedCornerRadii() { + final int newRoundedDefault = mContext.getResources().getDimensionPixelSize( + R.dimen.rounded_corner_radius); + final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize( + R.dimen.rounded_corner_radius_top); + final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize( + R.dimen.rounded_corner_radius_bottom); + + final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault + || mRoundedDefaultBottom != newRoundedDefaultBottom + || mRoundedDefaultTop != newRoundedDefaultTop; + + if (roundedCornersChanged) { + mRoundedDefault = newRoundedDefault; + mRoundedDefaultTop = newRoundedDefaultTop; + mRoundedDefaultBottom = newRoundedDefaultBottom; + onTuningChanged(SIZE, null); + } + } + private void updateViews() { View topLeft = mOverlay.findViewById(R.id.left); View topRight = mOverlay.findViewById(R.id.right); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 4e7c3ab26139..b96a6049421b 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -36,7 +36,7 @@ import com.android.systemui.plugins.OverlayPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarWindowManager; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.util.NotificationChannels; import java.util.HashMap; @@ -210,9 +210,9 @@ public class SystemUIApplication extends Application implements SysUiServiceProv if (mOverlays == null) mOverlays = new ArraySet<>(); if (plugin.holdStatusBarOpen()) { mOverlays.add(plugin); - Dependency.get(StatusBarWindowManager.class).setStateListener(b -> + Dependency.get(StatusBarWindowController.class).setStateListener(b -> mOverlays.forEach(o -> o.setCollapseDesired(b))); - Dependency.get(StatusBarWindowManager.class).setForcePluginOpen( + Dependency.get(StatusBarWindowController.class).setForcePluginOpen( mOverlays.size() != 0); } @@ -221,7 +221,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv @Override public void onPluginDisconnected(OverlayPlugin plugin) { mOverlays.remove(plugin); - Dependency.get(StatusBarWindowManager.class).setForcePluginOpen( + Dependency.get(StatusBarWindowController.class).setForcePluginOpen( mOverlays.size() != 0); } }, OverlayPlugin.class, true /* Allow multiple plugins */); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 311a2f214400..04d72cec402f 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -31,6 +31,7 @@ import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.qs.QSTileHost; import com.android.systemui.statusbar.KeyguardIndicationController; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -129,6 +130,7 @@ public class SystemUIFactory { public void injectDependencies(ArrayMap<Object, DependencyProvider> providers, Context context) { + providers.put(StatusBarStateController.class, StatusBarStateController::new); providers.put(NotificationLockscreenUserManager.class, () -> new NotificationLockscreenUserManager(context)); providers.put(VisualStabilityManager.class, VisualStabilityManager::new); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index 0ca0a117f6e6..3d578c39d3c4 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -36,6 +36,8 @@ import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; import com.android.systemui.analytics.DataCollector; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.util.AsyncSensorManager; import java.io.PrintWriter; @@ -82,6 +84,8 @@ public class FalsingManager implements SensorEventListener { private boolean mShowingAod; private Runnable mPendingWtf; + private final StateListener mStateListener = this::setStatusBarState; + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { @@ -104,6 +108,7 @@ public class FalsingManager implements SensorEventListener { UserHandle.USER_ALL); updateConfiguration(); + Dependency.get(StatusBarStateController.class).addListener(mStateListener); } public static FalsingManager getInstance(Context context) { @@ -274,7 +279,7 @@ public class FalsingManager implements SensorEventListener { updateSessionActive(); } - public void setStatusBarState(int state) { + private void setStatusBarState(int state) { if (FalsingLog.ENABLED) { FalsingLog.i("setStatusBarState", new StringBuilder() .append("from=").append(StatusBarState.toShortString(mState)) diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 10b92f78336f..92f5cae4e165 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -62,6 +62,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta private static final int TYPE_TILE = 0; private static final int TYPE_EDIT = 1; private static final int TYPE_ACCESSIBLE_DROP = 2; + private static final int TYPE_HEADER = 3; private static final int TYPE_DIVIDER = 4; private static final long EDIT_ID = 10000; @@ -112,7 +113,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta public void saveSpecs(QSTileHost host) { List<String> newSpecs = new ArrayList<>(); - for (int i = 0; i < mTiles.size() && mTiles.get(i) != null; i++) { + for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) { newSpecs.add(mTiles.get(i).spec); } host.changeTiles(mCurrentSpecs, newSpecs); @@ -145,6 +146,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta } mOtherTiles = new ArrayList<TileInfo>(mAllTiles); mTiles.clear(); + mTiles.add(null); for (int i = 0; i < mCurrentSpecs.size(); i++) { final TileInfo tile = getAndRemoveOther(mCurrentSpecs.get(i)); if (tile != null) { @@ -177,6 +179,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta @Override public int getItemViewType(int position) { + if (position == 0) { + return TYPE_HEADER; + } if (mAccessibilityAction == ACTION_ADD && position == mEditIndex - 1) { return TYPE_ACCESSIBLE_DROP; } @@ -193,6 +198,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta public Holder onCreateViewHolder(ViewGroup parent, int viewType) { final Context context = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(context); + if (viewType == TYPE_HEADER) { + return new Holder(inflater.inflate(R.layout.qs_customize_header, parent, false)); + } if (viewType == TYPE_DIVIDER) { return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false)); } @@ -218,6 +226,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta @Override public void onBindViewHolder(final Holder holder, int position) { + if (holder.getItemViewType() == TYPE_HEADER) { + return; + } if (holder.getItemViewType() == TYPE_DIVIDER) { holder.itemView.setVisibility(mTileDividerIndex < mTiles.size() - 1 ? View.VISIBLE : View.INVISIBLE); @@ -243,7 +254,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); holder.mTileView.setContentDescription(mContext.getString( R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, - position + 1)); + position)); holder.mTileView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -274,13 +285,13 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta R.string.accessibility_qs_edit_add_tile_label, info.state.label); } else if (mAccessibilityAction == ACTION_ADD) { info.state.contentDescription = mContext.getString( - R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position + 1); + R.string.accessibility_qs_edit_tile_add, mAccessibilityFromLabel, position); } else if (mAccessibilityAction == ACTION_MOVE) { info.state.contentDescription = mContext.getString( - R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position + 1); + R.string.accessibility_qs_edit_tile_move, mAccessibilityFromLabel, position); } else { info.state.contentDescription = mContext.getString( - R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label); + R.string.accessibility_qs_edit_tile_label, position, info.state.label); } holder.mTileView.handleStateChanged(info.state); holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem); @@ -403,11 +414,12 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta } private void updateDividerLocations() { - // The first null is the edit tiles label, the second null is the tile divider. - // If there is no second null, then there are no non-system tiles. + // The first null is the header label (index 0) so we can skip it, + // the second null is the edit tiles label, the third null is the tile divider. + // If there is no third null, then there are no non-system tiles. mEditIndex = -1; mTileDividerIndex = mTiles.size(); - for (int i = 0; i < mTiles.size(); i++) { + for (int i = 1; i < mTiles.size(); i++) { if (mTiles.get(i) == null) { if (mEditIndex == -1) { mEditIndex = i; @@ -486,7 +498,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta @Override public int getSpanSize(int position) { final int type = getItemViewType(position); - return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1; + return type == TYPE_EDIT || type == TYPE_DIVIDER || type == TYPE_HEADER ? 3 : 1; } }; @@ -511,7 +523,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final ViewHolder holder = parent.getChildViewHolder(child); - if (holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) { + if (holder.getAdapterPosition() == 0 || + holder.getAdapterPosition() < mEditIndex && !(child instanceof TextView)) { continue; } @@ -569,6 +582,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta @Override public boolean canDropOver(RecyclerView recyclerView, ViewHolder current, ViewHolder target) { + if (target.getAdapterPosition() == 0){ + return false; + } if (!canRemoveTiles() && current.getAdapterPosition() < mEditIndex) { return target.getAdapterPosition() < mEditIndex; } @@ -577,12 +593,17 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta @Override public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { - if (viewHolder.getItemViewType() == TYPE_EDIT || viewHolder.getItemViewType() == TYPE_DIVIDER) { - return makeMovementFlags(0, 0); + switch (viewHolder.getItemViewType()) { + case TYPE_EDIT: + case TYPE_DIVIDER: + case TYPE_HEADER: + // Fall through + return makeMovementFlags(0, 0); + default: + int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN + | ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT; + return makeMovementFlags(dragFlags, 0); } - int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT - | ItemTouchHelper.LEFT; - return makeMovementFlags(dragFlags, 0); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 6de054313cb7..929713c2c50b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.RemoteInput; import android.content.Context; @@ -113,7 +114,7 @@ public class NotificationRemoteInputManager implements Dumpable { } catch (RemoteException e) { } return mCallback.handleRemoteViewClick(view, pendingIntent, fillInIntent, - () -> superOnClickHandler(view, pendingIntent, fillInIntent)); + () -> super.onClickHandler(view, pendingIntent, fillInIntent)); } private void logActionClick(View view) { @@ -151,10 +152,11 @@ public class NotificationRemoteInputManager implements Dumpable { return null; } - private boolean superOnClickHandler(View view, PendingIntent pendingIntent, - Intent fillInIntent) { - return super.onClickHandler(view, pendingIntent, fillInIntent, - WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); + @Override + protected ActivityOptions getActivityOptions(Context context) { + ActivityOptions options = super.getActivityOptions(context); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); + return options; } private boolean handleRemoteInput(View view, PendingIntent pendingIntent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 55dfd440bcae..f7615e6448db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -34,8 +34,10 @@ import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.accessibility.AccessibilityNodeInfo; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -94,6 +96,8 @@ public class NotificationShelf extends ActivatableNotificationView implements private Rect mClipRect = new Rect(); private int mCutoutHeight; + private final StateListener mStateListener = this::setStatusBarState; + public NotificationShelf(Context context, AttributeSet attrs) { super(context, attrs); } @@ -114,6 +118,18 @@ public class NotificationShelf extends ActivatableNotificationView implements initDimens(); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(StatusBarStateController.class).addListener(mStateListener); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(StatusBarStateController.class).removeListener(mStateListener); + } + public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) { mAmbientState = ambientState; mHostLayout = hostLayout; @@ -836,11 +852,9 @@ public class NotificationShelf extends ActivatableNotificationView implements mCollapsedIcons.addOnLayoutChangeListener(this); } - public void setStatusBarState(int statusBarState) { - if (mStatusBarState != statusBarState) { - mStatusBarState = statusBarState; - updateInteractiveness(); - } + private void setStatusBarState(int statusBarState) { + mStatusBarState = statusBarState; + updateInteractiveness(); } private void updateInteractiveness() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java new file mode 100644 index 000000000000..7a69f2eee06c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java @@ -0,0 +1,91 @@ +/* + * 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; + +import android.util.ArraySet; + +/** + * Tracks and reports on {@link StatusBarState}. + */ +public class StatusBarStateController { + + private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER; + private static final int MIN_STATE = StatusBarState.SHADE; + + private final ArraySet<StateListener> mListeners = new ArraySet<>(); + private int mState; + private int mLastState; + private boolean mLeaveOpenOnKeyguardHide; + + public int getState() { + return mState; + } + + public void setState(int state) { + if (state > MAX_STATE || state < MIN_STATE) { + throw new IllegalArgumentException("Invalid state " + state); + } + if (state == mState) { + return; + } + synchronized (mListeners) { + for (StateListener listener : new ArraySet<>(mListeners)) { + listener.onStatePreChange(mState, state); + } + mLastState = mState; + mState = state; + for (StateListener listener : new ArraySet<>(mListeners)) { + listener.onStateChanged(mState); + } + } + } + + public boolean goingToFullShade() { + return mState == StatusBarState.SHADE && mLeaveOpenOnKeyguardHide; + } + + public void setLeaveOpenOnKeyguardHide(boolean leaveOpen) { + mLeaveOpenOnKeyguardHide = leaveOpen; + } + + public boolean leaveOpenOnKeyguardHide() { + return mLeaveOpenOnKeyguardHide; + } + + public boolean fromShadeLocked() { + return mLastState == StatusBarState.SHADE_LOCKED; + } + + public void addListener(StateListener listener) { + synchronized (mListeners) { + mListeners.add(listener); + } + } + + public void removeListener(StateListener listener) { + synchronized (mListeners) { + mListeners.remove(listener); + } + } + + public interface StateListener { + public default void onStatePreChange(int oldState, int newState) { + } + + public void onStateChanged(int newState); + } +} 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 6c9ca7037305..ed067525ed61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.car; -import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.car.user.CarUserManagerHelper; import android.graphics.PixelFormat; @@ -92,7 +91,7 @@ public class CarStatusBar extends StatusBar implements mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener); - mStackScroller.setScrollingEnabled(true); + mNotificationPanel.setScrollingEnabled(true); createBatteryController(); mCarBatteryController.startListening(); @@ -504,8 +503,8 @@ public class CarStatusBar extends StatusBar implements } @Override - public void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { - super.updateKeyguardState(goingToFullShade, fromShadeLocked); + public void onStateChanged(int newState) { + super.onStateChanged(newState); CarUserManagerHelper helper = new CarUserManagerHelper(mContext); if (!helper.isHeadlessSystemUser()) { showUserSwitcher(); 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 b376c007bbe4..da6401c2d62a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -164,7 +164,6 @@ public class UserGridRecyclerView extends PagedListView implements private final Resources mRes; private final String mGuestName; private final String mNewUserName; - private AlertDialog mDialog; // View that holds the add user button. Used to enable/disable the view private View mAddUserView; // User record for the add user. Need to call notifyUserSelected only if the user @@ -221,23 +220,9 @@ public class UserGridRecyclerView extends PagedListView implements // Disable button so it cannot be clicked multiple times mAddUserView = holder.mView; mAddUserView.setEnabled(false); - - String message = mRes.getString(R.string.user_add_user_message_setup) - .concat(System.getProperty("line.separator")) - .concat(System.getProperty("line.separator")) - .concat(mRes.getString(R.string.user_add_user_message_update)); - mAddUserRecord = userRecord; - mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert) - .setTitle(R.string.user_add_user_title) - .setMessage(message) - .setNegativeButton(android.R.string.cancel, this) - .setPositiveButton(android.R.string.ok, this) - .setOnCancelListener(this) - .create(); - // Sets window flags for the SysUI dialog - SystemUIDialog.applyFlags(mDialog); - mDialog.show(); + + handleAddUserClicked(); return; } // If the user doesn't want to be a guest or add a user, switch to the user selected @@ -247,6 +232,47 @@ public class UserGridRecyclerView extends PagedListView implements } + private void handleAddUserClicked() { + if (mCarUserManagerHelper.isUserLimitReached()) { + mAddUserView.setEnabled(true); + showMaxUserLimitReachedDialog(); + } else { + showConfirmAddUserDialog(); + } + } + + private void showMaxUserLimitReachedDialog() { + AlertDialog maxUsersDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert) + .setTitle(R.string.user_limit_reached_title) + .setMessage(getResources().getQuantityString( + R.plurals.user_limit_reached_message, + mCarUserManagerHelper.getMaxSupportedRealUsers(), + mCarUserManagerHelper.getMaxSupportedRealUsers())) + .setPositiveButton(android.R.string.ok, null) + .create(); + // Sets window flags for the SysUI dialog + SystemUIDialog.applyFlags(maxUsersDialog); + maxUsersDialog.show(); + } + + private void showConfirmAddUserDialog() { + String message = mRes.getString(R.string.user_add_user_message_setup) + .concat(System.getProperty("line.separator")) + .concat(System.getProperty("line.separator")) + .concat(mRes.getString(R.string.user_add_user_message_update)); + + AlertDialog addUserDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert) + .setTitle(R.string.user_add_user_title) + .setMessage(message) + .setNegativeButton(android.R.string.cancel, this) + .setPositiveButton(android.R.string.ok, this) + .setOnCancelListener(this) + .create(); + // Sets window flags for the SysUI dialog + SystemUIDialog.applyFlags(addUserDialog); + addUserDialog.show(); + } + private void notifyUserSelected(UserRecord userRecord) { // Notify the listener which user was selected if (mUserSelectionListener != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 1a1941edc2eb..53d38c49ec9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -29,13 +29,15 @@ import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.shared.system.SurfaceControlCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.StatusBar; @@ -57,6 +59,7 @@ public class ActivityLaunchAnimator { private final NotificationPanelView mNotificationPanel; private final NotificationListContainer mNotificationContainer; private final StatusBarWindowView mStatusBarWindow; + private final StatusBarStateController mStatusBarStateController; private StatusBar mStatusBar; private final Runnable mTimeoutRunnable = () -> { setAnimationPending(false); @@ -72,11 +75,12 @@ public class ActivityLaunchAnimator { mNotificationContainer = container; mStatusBarWindow = statusBarWindow; mStatusBar = statusBar; + mStatusBarStateController = Dependency.get(StatusBarStateController.class); } public RemoteAnimationAdapter getLaunchAnimation( ExpandableNotificationRow sourceNotification, boolean occluded) { - if (mStatusBar.getBarState() != StatusBarState.SHADE || occluded) { + if (mStatusBarStateController.getState() != StatusBarState.SHADE || occluded) { return null; } AnimationRunner animationRunner = new AnimationRunner(sourceNotification); @@ -91,7 +95,7 @@ public class ActivityLaunchAnimator { public void setLaunchResult(int launchResult) { setAnimationPending((launchResult == ActivityManager.START_TASK_TO_FRONT || launchResult == ActivityManager.START_SUCCESS) - && mStatusBar.getBarState() == StatusBarState.SHADE); + && mStatusBarStateController.getState() == StatusBarState.SHADE); } private void setAnimationPending(boolean pending) { 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 1393f8fed2ff..b655a6bab5b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -414,7 +414,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } else if (mListContainer.hasPulsingNotifications()) { dismissalSurface = NotificationStats.DISMISSAL_AOD; } - mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, nv); + int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL; + mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, + dismissalSentiment, nv); removeNotification(n.getKey(), null); } catch (RemoteException ex) { 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 094912b2cdc5..67db68deb928 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 @@ -1307,6 +1307,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } setDismissed(fromAccessibility); if (isClearable()) { + // TODO: track dismiss sentiment if (mOnDismissRunnable != null) { mOnDismissRunnable.run(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index ab47d3366b84..e635976310a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -28,12 +28,10 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; -import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; -import androidx.annotation.VisibleForTesting; import android.util.ArraySet; import android.util.Log; import android.view.HapticFeedbackConstants; @@ -45,15 +43,17 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.StatusBar; import java.io.FileDescriptor; import java.io.PrintWriter; +import androidx.annotation.VisibleForTesting; + /** * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and * closing guts, and keeping track of the currently exposed notification guts. @@ -147,15 +147,15 @@ public class NotificationGutsManager implements Dumpable { } } - public void bindGuts(final ExpandableNotificationRow row) { - bindGuts(row, mGutsMenuItem); + public boolean bindGuts(final ExpandableNotificationRow row) { + row.inflateGuts(); + return bindGuts(row, mGutsMenuItem); } - private void bindGuts(final ExpandableNotificationRow row, + private boolean bindGuts(final ExpandableNotificationRow row, NotificationMenuRowPlugin.MenuItem item) { StatusBarNotification sbn = row.getStatusBarNotification(); - row.inflateGuts(); row.setGutsView(item); row.setTag(sbn.getPackageName()); row.getGuts().setClosedListener((NotificationGuts g) -> { @@ -176,12 +176,18 @@ public class NotificationGutsManager implements Dumpable { }); View gutsView = item.getGutsView(); - if (gutsView instanceof NotificationSnooze) { - initializeSnoozeView(row, (NotificationSnooze) gutsView); - } else if (gutsView instanceof AppOpsInfo) { - initializeAppOpsInfo(row, (AppOpsInfo) gutsView); - } else if (gutsView instanceof NotificationInfo) { - initializeNotificationInfo(row, (NotificationInfo) gutsView); + try { + if (gutsView instanceof NotificationSnooze) { + initializeSnoozeView(row, (NotificationSnooze) gutsView); + } else if (gutsView instanceof AppOpsInfo) { + initializeAppOpsInfo(row, (AppOpsInfo) gutsView); + } else if (gutsView instanceof NotificationInfo) { + initializeNotificationInfo(row, (NotificationInfo) gutsView); + } + return true; + } catch (Exception e) { + Log.e(TAG, "error binding guts", e); + return false; } } @@ -240,7 +246,7 @@ public class NotificationGutsManager implements Dumpable { @VisibleForTesting void initializeNotificationInfo( final ExpandableNotificationRow row, - NotificationInfo notificationInfoView) { + NotificationInfo notificationInfoView) throws Exception { NotificationGuts guts = row.getGuts(); StatusBarNotification sbn = row.getStatusBarNotification(); String packageName = sbn.getPackageName(); @@ -269,24 +275,21 @@ public class NotificationGutsManager implements Dumpable { }; } - try { - notificationInfoView.bindNotification( - pmUser, - iNotificationManager, - packageName, - row.getEntry().channel, - row.getNumUniqueChannels(), - sbn, - mCheckSaveListener, - onSettingsClick, - onAppSettingsClick, - mPresenter.isDeviceProvisioned(), - row.getIsNonblockable(), - isForBlockingHelper, - row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } + notificationInfoView.bindNotification( + pmUser, + iNotificationManager, + packageName, + row.getEntry().channel, + row.getNumUniqueChannels(), + sbn, + mCheckSaveListener, + onSettingsClick, + onAppSettingsClick, + mPresenter.isDeviceProvisioned(), + row.getIsNonblockable(), + isForBlockingHelper, + row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE); + } /** @@ -356,8 +359,15 @@ public class NotificationGutsManager implements Dumpable { true /* resetMenu */); return false; } - bindGuts(row, menuItem); + + row.inflateGuts(); NotificationGuts guts = row.getGuts(); + mNotificationGutsExposed = guts; + if (!bindGuts(row, menuItem)) { + // exception occurred trying to fill in all the data, bail. + return false; + } + // Assume we are a status_bar_notification_row if (guts == null) { @@ -378,9 +388,6 @@ public class NotificationGutsManager implements Dumpable { + "window"); return; } - closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, - true /* removeControls */, -1 /* x */, -1 /* y */, - false /* resetMenu */); guts.setVisibility(View.VISIBLE); final boolean needsFalsingProtection = @@ -396,7 +403,6 @@ public class NotificationGutsManager implements Dumpable { row.closeRemoteInput(); mListContainer.onHeightChanged(row, true /* needsAnimation */); - mNotificationGutsExposed = guts; mGutsMenuItem = menuItem; } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index bb07f331910f..15eaaaca2842 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -21,12 +21,12 @@ import android.content.Context; import android.view.View; import com.android.systemui.R; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.NotificationShelf; -import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.HeadsUpManager; import java.util.ArrayList; 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 987de0e2a646..4f554b656b26 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 @@ -28,7 +28,9 @@ import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.FloatRange; import android.annotation.Nullable; +import android.app.WallpaperManager; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Canvas; @@ -40,16 +42,22 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; +import android.os.ServiceManager; +import android.provider.Settings; import android.service.notification.StatusBarNotification; + import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.core.graphics.ColorUtils; + import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Log; import android.util.MathUtils; import android.util.Pair; import android.view.ContextThemeWrapper; import android.view.InputDevice; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -66,21 +74,36 @@ import android.widget.ScrollView; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.statusbar.IStatusBarService; import com.android.keyguard.KeyguardSliceView; import com.android.settingslib.Utils; import com.android.systemui.Dependency; +import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.SwipeHelper; +import com.android.systemui.SwipeHelper.Callback; 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; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener; import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.NotificationData; @@ -89,17 +112,23 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.row.NotificationSnooze; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone.AnimationStateHandler; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener; import com.android.systemui.statusbar.phone.NotificationIconAreaController; +import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.ScrollAdapter; @@ -116,10 +145,11 @@ 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 SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter, - ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener, - NotificationMenuRowPlugin.OnMenuEventListener, VisibilityLocationProvider, - NotificationListContainer { + implements Callback, ExpandHelper.Callback, ScrollAdapter, + OnHeightChangedListener, OnGroupChangeListener, + OnMenuEventListener, VisibilityLocationProvider, + NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler, + Dumpable { public static final float BACKGROUND_ALPHA_DIMMED = 0.7f; private static final String TAG = "StackScroller"; @@ -416,8 +446,27 @@ public class NotificationStackScrollLayout extends ViewGroup private HeadsUpAppearanceController mHeadsUpAppearanceController; private NotificationIconAreaController mIconAreaController; private float mVerticalPanelTranslation; + private final NotificationLockscreenUserManager mLockscreenUserManager = + Dependency.get(NotificationLockscreenUserManager.class); + private final Rect mTmpRect = new Rect(); + private final NotificationEntryManager mEntryManager = + Dependency.get(NotificationEntryManager.class); + private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); + private final NotificationRemoteInputManager mRemoteInputManager = + Dependency.get(NotificationRemoteInputManager.class); + private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class); + + private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class); + private final LockscreenGestureLogger mLockscreenGestureLogger = + Dependency.get(LockscreenGestureLogger.class); + private final VisualStabilityManager mVisualStabilityManager = + Dependency.get(VisualStabilityManager.class); + protected boolean mClearAllEnabled; private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN; + private NotificationPanelView mNotificationPanel; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -474,6 +523,102 @@ public class NotificationStackScrollLayout extends ViewGroup mDebugPaint.setStrokeWidth(2); mDebugPaint.setStyle(Paint.Style.STROKE); } + mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + inflateEmptyShadeView(); + inflateFooterView(); + mVisualStabilityManager.setVisibilityLocationProvider(this); + setLongPressListener(mEntryManager.getNotificationLongClicker()); + } + + @Override + public void onDensityOrFontScaleChanged() { + inflateFooterView(); + inflateEmptyShadeView(); + updateFooter(); + } + + @Override + public void onThemeChanged() { + int which; + if (mStatusBarState == StatusBarState.KEYGUARD + || mStatusBarState == StatusBarState.SHADE_LOCKED) { + which = WallpaperManager.FLAG_LOCK; + } else { + which = WallpaperManager.FLAG_SYSTEM; + } + final boolean useDarkText = mColorExtractor.getColors(which, + true /* ignoreVisibility */).supportsDarkText(); + updateDecorViews(useDarkText); + + updateFooter(); + } + + @VisibleForTesting + public void updateFooter() { + boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(); + boolean showFooterView = (showDismissView || + mEntryManager.getNotificationData().getActiveNotifications().size() != 0) + && mStatusBarState != StatusBarState.KEYGUARD + && !mRemoteInputManager.getController().isRemoteInputActive(); + + updateFooterView(showFooterView, showDismissView); + } + + /** + * Return whether there are any clearable notifications + */ + public boolean hasActiveClearableNotifications() { + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (!(child instanceof ExpandableNotificationRow)) { + continue; + } + if (((ExpandableNotificationRow) child).canViewBeDismissed()) { + return true; + } + } + return false; + } + + public RemoteInputController.Delegate createDelegate() { + return new RemoteInputController.Delegate() { + public void setRemoteInputActive(NotificationData.Entry entry, + boolean remoteInputActive) { + mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); + entry.row.notifyHeightChanged(true /* needsAnimation */); + updateFooter(); + } + + public void lockScrollTo(NotificationData.Entry entry) { + NotificationStackScrollLayout.this.lockScrollTo(entry.row); + } + + public void requestDisallowLongPressAndDismiss() { + requestDisallowLongPress(); + requestDisallowDismiss(); + } + }; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(StatusBarStateController.class).addListener(mStateListener); + Dependency.get(ConfigurationController.class).addCallback(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(StatusBarStateController.class).removeListener(mStateListener); + Dependency.get(ConfigurationController.class).removeCallback(this); } @Override @@ -513,6 +658,7 @@ public class NotificationStackScrollLayout extends ViewGroup mSwipeHelper.onMenuShown(row); } + @Override public void onUiModeChanged() { mBgColor = mContext.getColor(R.color.notification_shade_background_color); updateBackgroundDimming(); @@ -790,8 +936,8 @@ public class NotificationStackScrollLayout extends ViewGroup private void updateClippingToTopRoundedCorner() { Float clipStart = (float) mTopPadding - + mStackTranslation - + mAmbientState.getExpandAnimationTopChange(); + + mStackTranslation + + mAmbientState.getExpandAnimationTopChange(); Float clipEnd = clipStart + mCornerRadius; boolean first = true; for (int i = 0; i < getChildCount(); i++) { @@ -823,7 +969,8 @@ public class NotificationStackScrollLayout extends ViewGroup : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements; int childHeight = getIntrinsicHeight(child) + padding; if (startingPosition < mOwnScrollY) { - // This child starts off screen, so let's keep it offscreen to keep the others visible + // This child starts off screen, so let's keep it offscreen to keep the + // others visible setOwnScrollY(mOwnScrollY + childHeight); } @@ -885,7 +1032,7 @@ public class NotificationStackScrollLayout extends ViewGroup updateContentHeight(); if (animate && mAnimationsEnabled && mIsExpanded) { mTopPaddingNeedsAnimation = true; - mNeedsAnimation = true; + mNeedsAnimation = true; } requestChildrenUpdate(); notifyHeightChangeListener(null, animate); @@ -995,7 +1142,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return The translation at the beginning when expanding. - * Measured relative to the resting position. + * Measured relative to the resting position. */ private float getExpandTranslationStart() { return -mTopPadding + getMinExpansionHeight(); @@ -1003,7 +1150,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return the position from where the appear transition starts when expanding. - * Measured in absolute height. + * Measured in absolute height. */ private float getAppearStartPosition() { if (isHeadsUpTransition()) { @@ -1014,8 +1161,8 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return the height of the top heads up notification when pinned. This is different from the - * intrinsic height, which also includes whether the notification is system expanded and - * is mainly used when dragging down from a heads up notification. + * intrinsic height, which also includes whether the notification is system expanded and + * is mainly used when dragging down from a heads up notification. */ private int getTopHeadsUpPinnedHeight() { NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry(); @@ -1035,7 +1182,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return the position from where the appear transition ends when expanding. - * Measured in absolute height. + * Measured in absolute height. */ private float getAppearEndPosition() { int appearPosition; @@ -1241,9 +1388,9 @@ public class NotificationStackScrollLayout extends ViewGroup ExpandableNotificationRow parent = row.getNotificationParent(); if (parent != null && parent.areChildrenExpanded() && (parent.areGutsExposed() - || mMenuExposedView == parent - || (parent.getNotificationChildren().size() == 1 - && parent.isClearable()))) { + || 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 @@ -1298,8 +1445,8 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Get the child at a certain screen location. * - * @param touchX the x coordinate - * @param touchY the y coordinate + * @param touchX the x coordinate + * @param touchY the y coordinate * @param requireMinHeight Whether a minimum height is required for a child to be returned. * @return the child at the given location. */ @@ -1330,8 +1477,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (!mIsExpanded && row.isHeadsUp() && row.isPinned() && mHeadsUpManager.getTopEntry().row != row && mGroupManager.getGroupSummary( - mHeadsUpManager.getTopEntry().row.getStatusBarNotification()) - != row) { + mHeadsUpManager.getTopEntry().row.getStatusBarNotification()) + != row) { continue; } return row.getViewAtPosition(touchY - childTop); @@ -1434,7 +1581,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return the scroll necessary to make the bottom edge of {@param v} align with the top of - * the IME. + * the IME. */ private int targetScrollForView(ExpandableView v, int positionInLinearLayout) { return positionInLinearLayout + v.getIntrinsicHeight() + @@ -1471,7 +1618,7 @@ public class NotificationStackScrollLayout extends ViewGroup } }; - public void setExpandingEnabled(boolean enable) { + private void setExpandingEnabled(boolean enable) { mExpandHelper.setEnabled(enable); } @@ -1495,7 +1642,7 @@ public class NotificationStackScrollLayout extends ViewGroup private void setSwipingInProgress(boolean isSwiped) { mSwipingInProgress = isSwiped; - if(isSwiped) { + if (isSwiped) { requestDisallowInterceptTouchEvent(true); } } @@ -1532,7 +1679,7 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public boolean onTouchEvent(MotionEvent ev) { boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL - || ev.getActionMasked()== MotionEvent.ACTION_UP; + || ev.getActionMasked() == MotionEvent.ACTION_UP; handleEmptySpaceClick(ev); boolean expandWantsIt = false; if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) { @@ -1771,7 +1918,7 @@ public class NotificationStackScrollLayout extends ViewGroup * * @param deltaY The amount to scroll upwards, has to be positive. * @return The amount of scrolling to be performed by the scroller, - * not handled by the overScroll amount. + * not handled by the overScroll amount. */ private float overScrollUp(int deltaY, int range) { deltaY = Math.max(deltaY, 0); @@ -1804,7 +1951,7 @@ public class NotificationStackScrollLayout extends ViewGroup * * @param deltaY The amount to scroll downwards, has to be negative. * @return The amount of scrolling to be performed by the scroller, - * not handled by the overScroll amount. + * not handled by the overScroll amount. */ private float overScrollDown(int deltaY) { deltaY = Math.min(deltaY, 0); @@ -1930,8 +2077,8 @@ public class NotificationStackScrollLayout extends ViewGroup * * @param numPixels The amount of pixels to overScroll by. These will be scaled according to * the rubber-banding logic. - * @param onTop Should the effect be applied on top of the scroller. - * @param animate Should an animation be performed. + * @param onTop Should the effect be applied on top of the scroller. + * @param animate Should an animation be performed. */ public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) { setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true); @@ -1941,8 +2088,8 @@ public class NotificationStackScrollLayout extends ViewGroup * Set the effective overScroll amount which will be directly reflected in the layout. * By default this will also cancel animations on the same overScroll edge. * - * @param amount The amount to overScroll by. - * @param onTop Should the effect be applied on top of the scroller. + * @param amount The amount to overScroll by. + * @param onTop Should the effect be applied on top of the scroller. * @param animate Should an animation be performed. */ public void setOverScrollAmount(float amount, boolean onTop, boolean animate) { @@ -1952,9 +2099,9 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Set the effective overScroll amount which will be directly reflected in the layout. * - * @param amount The amount to overScroll by. - * @param onTop Should the effect be applied on top of the scroller. - * @param animate Should an animation be performed. + * @param amount The amount to overScroll by. + * @param onTop Should the effect be applied on top of the scroller. + * @param animate Should an animation be performed. * @param cancelAnimators Should running animations be cancelled. */ public void setOverScrollAmount(float amount, boolean onTop, boolean animate, @@ -1965,12 +2112,12 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Set the effective overScroll amount which will be directly reflected in the layout. * - * @param amount The amount to overScroll by. - * @param onTop Should the effect be applied on top of the scroller. - * @param animate Should an animation be performed. + * @param amount The amount to overScroll by. + * @param onTop Should the effect be applied on top of the scroller. + * @param animate Should an animation be performed. * @param cancelAnimators Should running animations be cancelled. - * @param isRubberbanded The value which will be passed to - * {@link OnOverscrollTopChangedListener#onOverscrollTopChanged} + * @param isRubberbanded The value which will be passed to + * {@link OnOverscrollTopChangedListener#onOverscrollTopChanged} */ public void setOverScrollAmount(float amount, boolean onTop, boolean animate, boolean cancelAnimators, boolean isRubberbanded) { @@ -2016,7 +2163,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public float getCurrentOverScrolledPixels(boolean top) { - return top? mOverScrolledTopPixels : mOverScrolledBottomPixels; + return top ? mOverScrolledTopPixels : mOverScrolledBottomPixels; } private void setOverScrolledPixels(float amount, boolean onTop) { @@ -2120,7 +2267,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @return The first child which has visibility unequal to GONE which is currently below the - * given translationY or equal to it. + * given translationY or equal to it. */ private View getFirstChildBelowTranlsationY(float translationY, boolean ignoreChildren) { int childCount = getChildCount(); @@ -2577,7 +2724,7 @@ public class NotificationStackScrollLayout extends ViewGroup setOverScrollAmount(0, false, false); mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(false /* onTop */) * mOverflingDistance - + bottomAmount; + + bottomAmount; } else { // it will be set once we reach the boundary mMaxOverScroll = 0.0f; @@ -2609,8 +2756,8 @@ public class NotificationStackScrollLayout extends ViewGroup * Updates the top padding of the notifications, taking {@link #getIntrinsicPadding()} into * account. * - * @param qsHeight the top padding imposed by the quick settings panel - * @param animate whether to animate the change + * @param qsHeight the top padding imposed by the quick settings panel + * @param animate whether to animate the change * @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and * {@code qsHeight} is the final top padding */ @@ -2753,7 +2900,7 @@ public class NotificationStackScrollLayout extends ViewGroup switch (ev.getActionMasked()) { case MotionEvent.ACTION_MOVE: if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop - || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop )) { + || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop)) { mTouchIsClick = false; } break; @@ -2854,7 +3001,7 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean isChildInGroup(View child) { return child instanceof ExpandableNotificationRow && mGroupManager.isChildInGroupWithSummary( - ((ExpandableNotificationRow) child).getStatusBarNotification()); + ((ExpandableNotificationRow) child).getStatusBarNotification()); } /** @@ -2910,7 +3057,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (hasAddEvent) { // This child was just added lets remove all events. mHeadsUpChangeAnimations.removeAll(mTmpList); - ((ExpandableNotificationRow ) child).setHeadsUpAnimatingAway(false); + ((ExpandableNotificationRow) child).setHeadsUpAnimatingAway(false); } mTmpList.clear(); return hasAddEvent; @@ -2919,7 +3066,7 @@ public class NotificationStackScrollLayout extends ViewGroup /** * @param child the child to query * @return whether a view is not a top level child but a child notification and that group is - * not expanded + * not expanded */ private boolean isChildInInvisibleGroup(View child) { if (child instanceof ExpandableNotificationRow) { @@ -3164,7 +3311,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (currentIndex == -1) { boolean isTransient = false; if (child instanceof ExpandableNotificationRow - && ((ExpandableNotificationRow)child).getTransientContainer() != null) { + && ((ExpandableNotificationRow) child).getTransientContainer() != null) { isTransient = true; } Log.e(TAG, "Attempting to re-position " @@ -3177,10 +3324,10 @@ public class NotificationStackScrollLayout extends ViewGroup if (child != null && child.getParent() == this && currentIndex != newIndex) { mChangePositionInProgress = true; - ((ExpandableView)child).setChangingPosition(true); + ((ExpandableView) child).setChangingPosition(true); removeView(child); addView(child, newIndex); - ((ExpandableView)child).setChangingPosition(false); + ((ExpandableView) child).setChangingPosition(false); mChangePositionInProgress = false; if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) { mChildrenChangingPositions.add(child); @@ -3291,7 +3438,7 @@ public class NotificationStackScrollLayout extends ViewGroup for (AnimationEvent animationEvent : mAnimationEvents) { final int type = animationEvent.animationType; if (type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK - || type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) { + || type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) { hasDisappearAnimation = true; break; } @@ -3470,10 +3617,10 @@ public class NotificationStackScrollLayout extends ViewGroup */ /* - * Shortcut the most recurring case: the user is in the dragging - * state and is moving their finger. We want to intercept this - * motion. - */ + * Shortcut the most recurring case: the user is in the dragging + * state and is moving their finger. We want to intercept this + * motion. + */ final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; @@ -3487,9 +3634,9 @@ public class NotificationStackScrollLayout extends ViewGroup */ /* - * Locally do absolute value. mLastMotionY is set to the y value - * of the down event. - */ + * Locally do absolute value. mLastMotionY is set to the y value + * of the down event. + */ final int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on content. @@ -3537,10 +3684,10 @@ public class NotificationStackScrollLayout extends ViewGroup initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); /* - * If being flinged and user touches the screen, initiate drag; - * otherwise don't. mScroller.isFinished should be false when - * being flinged. - */ + * If being flinged and user touches the screen, initiate drag; + * otherwise don't. mScroller.isFinished should be false when + * being flinged. + */ boolean isBeingDragged = !mScroller.isFinished(); setIsBeingDragged(isBeingDragged); break; @@ -3562,9 +3709,9 @@ public class NotificationStackScrollLayout extends ViewGroup } /* - * The only time we want to intercept motion events is if we are in the - * drag mode. - */ + * The only time we want to intercept motion events is if we are in the + * drag mode. + */ return mIsBeingDragged; } @@ -3704,6 +3851,7 @@ public class NotificationStackScrollLayout extends ViewGroup mPanelTracking = true; mAmbientState.setPanelTracking(true); } + public void onPanelTrackingStopped() { mPanelTracking = false; mAmbientState.setPanelTracking(false); @@ -3846,7 +3994,7 @@ public class NotificationStackScrollLayout extends ViewGroup mAmbientState.setDimmed(dimmed); if (animate && mAnimationsEnabled) { mDimmedNeedsAnimation = true; - mNeedsAnimation = true; + mNeedsAnimation = true; animateDimmed(dimmed); } else { setDimAmount(dimmed ? 1.0f : 0.0f); @@ -3880,7 +4028,7 @@ public class NotificationStackScrollLayout extends ViewGroup mDimAnimator.start(); } - public void setHideSensitive(boolean hideSensitive, boolean animate) { + private void setHideSensitive(boolean hideSensitive, boolean animate) { if (hideSensitive != mAmbientState.isHideSensitive()) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -3890,7 +4038,7 @@ public class NotificationStackScrollLayout extends ViewGroup mAmbientState.setHideSensitive(hideSensitive); if (animate && mAnimationsEnabled) { mHideSensitiveNeedsAnimation = true; - mNeedsAnimation = true; + mNeedsAnimation = true; } updateContentHeight(); requestChildrenUpdate(); @@ -3904,7 +4052,7 @@ public class NotificationStackScrollLayout extends ViewGroup mAmbientState.setActivatedChild(activatedChild); if (mAnimationsEnabled) { mActivateNeedsAnimation = true; - mNeedsAnimation = true; + mNeedsAnimation = true; } requestChildrenUpdate(); } @@ -4059,10 +4207,11 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Sets the current dark amount. * - * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation, - * i.e. animates from 0 to 1 or vice-versa in a linear manner. + * @param linearDarkAmount The dark amount that follows linear interpoloation in the + * animation, + * i.e. animates from 0 to 1 or vice-versa in a linear manner. * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the - * animation curve. + * animation curve. */ public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) { mLinearDarkAmount = linearDarkAmount; @@ -4240,10 +4389,7 @@ public class NotificationStackScrollLayout extends ViewGroup public void setGroupManager(NotificationGroupManager groupManager) { this.mGroupManager = groupManager; - } - - public void onGoToKeyguard() { - requestAnimateEverything(); + mGroupManager.setOnGroupChangeListener(this); } private void requestAnimateEverything() { @@ -4267,15 +4413,15 @@ public class NotificationStackScrollLayout extends ViewGroup boolean belowChild = touchY > childTop + child.getActualHeight() - child.getClipBottomAmount(); if (child == mFooterView) { - if(!belowChild && !mFooterView.isOnEmptySpace(touchX - mFooterView.getX(), - touchY - childTop)) { + if (!belowChild && !mFooterView.isOnEmptySpace(touchX - mFooterView.getX(), + touchY - childTop)) { // We clicked on the dismiss button return false; } } else if (child == mEmptyShadeView) { // We arrived at the empty shade view, for which we accept all clicks return true; - } else if (!belowChild){ + } else if (!belowChild) { // We are on a child return false; } @@ -4413,6 +4559,7 @@ public class NotificationStackScrollLayout extends ViewGroup mHeadsUpManager = headsUpManager; mAmbientState.setHeadsUpManager(headsUpManager); mHeadsUpManager.addListener(mRoundnessManager); + mHeadsUpManager.setAnimationStateHandler(this); } public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) { @@ -4435,7 +4582,7 @@ public class NotificationStackScrollLayout extends ViewGroup * Set the boundary for the bottom heads up position. The heads up will always be above this * position. * - * @param height the height of the screen + * @param height the height of the screen * @param bottomBarHeight the height of the bar on the bottom */ public void setHeadsUpBoundaries(int height, int bottomBarHeight) { @@ -4578,7 +4725,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) { - mShouldShowShelfOnly = shouldShowShelfOnly; + mShouldShowShelfOnly = shouldShowShelfOnly; updateAlgorithmLayoutMinHeight(); } @@ -4596,9 +4743,27 @@ public class NotificationStackScrollLayout extends ViewGroup updateClipping(); } - public void setStatusBarState(int statusBarState) { + private void setStatusBarState(int statusBarState) { mStatusBarState = statusBarState; mAmbientState.setStatusBarState(statusBarState); + boolean onKeyguard = onKeyguard(); + boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode(); + if (mHeadsUpAppearanceController != null) { + mHeadsUpAppearanceController.setPublicMode(publicMode); + } + + StatusBarStateController state = Dependency.get(StatusBarStateController.class); + setHideSensitive(publicMode, state.goingToFullShade() /* animate */); + setDimmed(onKeyguard, state.fromShadeLocked() /* animate */); + setExpandingEnabled(!onKeyguard); + ActivatableNotificationView activatedChild = getActivatedChild(); + setActivatedChild(null); + if (activatedChild != null) { + activatedChild.makeInactive(false /* animate */); + } + updateFooter(); + updateChildren(); + onUpdateRowStates(); } public void setExpandingVelocity(float expandingVelocity) { @@ -4626,6 +4791,7 @@ public class NotificationStackScrollLayout extends ViewGroup requestChildrenUpdate(); } + @Override public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) { mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed; } @@ -4640,15 +4806,15 @@ public class NotificationStackScrollLayout extends ViewGroup + " alpha:%f scrollY:%d maxTopPadding:%d showShelfOnly=%s" + " qsExpandFraction=%f]", this.getClass().getSimpleName(), - mPulsing ? "T":"f", - mAmbientState.isQsCustomizerShowing() ? "T":"f", + mPulsing ? "T" : "f", + mAmbientState.isQsCustomizerShowing() ? "T" : "f", getVisibility() == View.VISIBLE ? "visible" : getVisibility() == View.GONE ? "gone" : "invisible", getAlpha(), mAmbientState.getScrollY(), mMaxTopPadding, - mShouldShowShelfOnly ? "T":"f", + mShouldShowShelfOnly ? "T" : "f", mQsExpansionFraction)); } @@ -4682,6 +4848,150 @@ public class NotificationStackScrollLayout extends ViewGroup mIconAreaController = controller; } + public void manageNotifications(View v) { + Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS); + mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); + } + + public void clearAllNotifications() { + // animate-swipe all dismissable notifications, then animate the shade closed + int numChildren = getChildCount(); + + final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); + final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); + for (int i = 0; i < numChildren; i++) { + final View child = getChildAt(i); + if (child instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + boolean parentVisible = false; + boolean hasClipBounds = child.getClipBounds(mTmpRect); + if (canChildBeDismissed(child)) { + viewsToRemove.add(row); + if (child.getVisibility() == View.VISIBLE + && (!hasClipBounds || mTmpRect.height() > 0)) { + viewsToHide.add(child); + parentVisible = true; + } + } else if (child.getVisibility() == View.VISIBLE + && (!hasClipBounds || mTmpRect.height() > 0)) { + parentVisible = true; + } + List<ExpandableNotificationRow> children = row.getNotificationChildren(); + if (children != null) { + for (ExpandableNotificationRow childRow : children) { + viewsToRemove.add(childRow); + if (parentVisible && row.areChildrenExpanded() + && canChildBeDismissed(childRow)) { + hasClipBounds = childRow.getClipBounds(mTmpRect); + if (childRow.getVisibility() == View.VISIBLE + && (!hasClipBounds || mTmpRect.height() > 0)) { + viewsToHide.add(childRow); + } + } + } + } + } + } + if (viewsToRemove.isEmpty()) { + mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + return; + } + + mStatusBar.addPostCollapseAction(() -> { + setDismissAllInProgress(false); + for (ExpandableNotificationRow rowToRemove : viewsToRemove) { + if (canChildBeDismissed(rowToRemove)) { + mEntryManager.removeNotification(rowToRemove.getEntry().key, null); + } else { + rowToRemove.resetTranslation(); + } + } + try { + mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId()); + } catch (Exception ex) { + } + }); + + performDismissAllAnimations(viewsToHide); + } + + public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { + Runnable animationFinishAction = () -> { + mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + }; + + if (hideAnimatedList.isEmpty()) { + animationFinishAction.run(); + return; + } + + // let's disable our normal animations + setDismissAllInProgress(true); + + // Decrease the delay for every row we animate to give the sense of + // accelerating the swipes + int rowDelayDecrement = 10; + int currentDelay = 140; + int totalDelay = 180; + int numItems = hideAnimatedList.size(); + for (int i = numItems - 1; i >= 0; i--) { + View view = hideAnimatedList.get(i); + Runnable endRunnable = null; + if (i == 0) { + endRunnable = animationFinishAction; + } + dismissViewAnimated(view, endRunnable, totalDelay, 260); + currentDelay = Math.max(50, currentDelay - rowDelayDecrement); + totalDelay += currentDelay; + } + } + + @VisibleForTesting + protected void inflateFooterView() { + FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate( + R.layout.status_bar_notification_footer, this, false); + footerView.setDismissButtonClickListener(v -> { + mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); + clearAllNotifications(); + }); + footerView.setManageButtonClickListener(this::manageNotifications); + setFooterView(footerView); + } + + 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); + setEmptyShadeView(view); + } + + /** + * Updates expanded, dimmed and locked states of notification rows. + */ + public void onUpdateRowStates() { + changeViewPosition(mFooterView, -1); + + // The following views will be moved to the end of mStackScroller. This counter represents + // the offset from the last child. Initialized to 1 for the very last position. It is post- + // incremented in the following "changeViewPosition" calls so that its value is correct for + // subsequent calls. + int offsetFromEnd = 1; + changeViewPosition(mEmptyShadeView, + getChildCount() - offsetFromEnd++); + + // No post-increment for this call because it is the last one. Make sure to add one if + // another "changeViewPosition" call is ever added. + changeViewPosition(mShelf, + getChildCount() - offsetFromEnd); + + // Scrim opacity varies based on notification count + mScrimController.setNotificationCount(getNotGoneChildCount()); + } + + public void setNotificationPanel(NotificationPanelView notificationPanelView) { + mNotificationPanel = notificationPanelView; + } + /** * A listener that is notified when the empty space below the notifications is clicked on */ @@ -4697,10 +5007,11 @@ public class NotificationStackScrollLayout extends ViewGroup /** * Notifies a listener that the overscroll has changed. * - * @param amount the amount of overscroll, in pixels + * @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) + * unrubberbanded motion to directly expand overscroll view (e.g + * expand + * QS) */ void onOverscrollTopChanged(float amount, boolean isRubberbanded); @@ -4709,7 +5020,7 @@ public class NotificationStackScrollLayout extends ViewGroup * 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. + * @param open Should the fling open or close the overscroll view. */ void flingTopOverscroll(float velocity, boolean open); } @@ -4910,6 +5221,84 @@ public class NotificationStackScrollLayout extends ViewGroup } } + public boolean hasActiveNotifications() { + return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty(); + } + + // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ + + + /* Only ever called as a consequence of a lockscreen expansion gesture. */ + @Override + public boolean onDraggedDown(View startingChild, int dragLengthY) { + if (mStatusBarState == StatusBarState.KEYGUARD + && hasActiveNotifications() && (!mStatusBar.isDozing() || mStatusBar.isPulsing())) { + mLockscreenGestureLogger.write( + MetricsEvent.ACTION_LS_SHADE, + (int) (dragLengthY / mDisplayMetrics.density), + 0 /* velocityDp - N/A */); + + // We have notifications, go to locked shade. + mStatusBar.goToLockedShade(startingChild); + if (startingChild instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; + row.onExpandedByGesture(true /* drag down is always an open */); + } + return true; + } else { + // abort gesture. + return false; + } + } + + @Override + public void onDragDownReset() { + setDimmed(true /* dimmed */, true /* animated */); + resetScrollPosition(); + resetCheckSnoozeLeavebehind(); + } + + @Override + public void onCrossedThreshold(boolean above) { + setDimmed(!above /* dimmed */, true /* animate */); + } + + @Override + public void onTouchSlopExceeded() { + cancelLongPress(); + checkSnoozeLeavebehind(); + } + + @Override + public void setEmptyDragAmount(float amount) { + mNotificationPanel.setEmptyDragAmount(amount); + } + + @Override + public boolean isFalsingCheckNeeded() { + return mStatusBarState == StatusBarState.KEYGUARD; + } + + public void updateSpeedBumpIndex() { + int speedBumpIndex = 0; + int currentIndex = 0; + final int N = getChildCount(); + for (int i = 0; i < N; i++) { + View view = getChildAt(i); + if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) { + continue; + } + ExpandableNotificationRow row = (ExpandableNotificationRow) view; + currentIndex++; + if (!mEntryManager.getNotificationData().isAmbient( + row.getStatusBarNotification().getKey())) { + speedBumpIndex = currentIndex; + } + } + boolean noAmbient = speedBumpIndex == N; + updateSpeedBumpIndex(speedBumpIndex, noAmbient); + } + private boolean isTouchInView(MotionEvent ev, View view) { if (view == null) { return false; @@ -4951,7 +5340,7 @@ public class NotificationStackScrollLayout extends ViewGroup static class AnimationEvent { - static AnimationFilter[] FILTERS = new AnimationFilter[] { + static AnimationFilter[] FILTERS = new AnimationFilter[]{ // ANIMATION_TYPE_ADD new AnimationFilter() @@ -5108,7 +5497,7 @@ public class NotificationStackScrollLayout extends ViewGroup .animateY(), }; - static int[] LENGTHS = new int[] { + static int[] LENGTHS = new int[]{ // ANIMATION_TYPE_ADD StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR, @@ -5233,7 +5622,7 @@ public class NotificationStackScrollLayout extends ViewGroup * * @param events The events of the lengths to combine. * @return The combined length. Depending on the event types, this might be the maximum of - * all events or the length of a specific event. + * all events or the length of a specific event. */ static long combineLength(ArrayList<AnimationEvent> events) { long length = 0; @@ -5248,4 +5637,18 @@ public class NotificationStackScrollLayout extends ViewGroup return length; } } + + private final StateListener mStateListener = new StateListener() { + @Override + public void onStatePreChange(int oldState, int newState) { + if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) { + requestAnimateEverything(); + } + } + + @Override + public void onStateChanged(int newState) { + setStatusBarState(newState); + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 2087a165b215..b57a366d6ef2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -101,7 +101,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { private KeyguardUpdateMonitor mUpdateMonitor; private int mMode; private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private StatusBarWindowManager mStatusBarWindowManager; + private StatusBarWindowController mStatusBarWindowController; private DozeScrimController mDozeScrimController; private KeyguardViewMediator mKeyguardViewMediator; private ScrimController mScrimController; @@ -125,7 +125,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { mUpdateMonitor.registerCallback(this); Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver); Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver); - mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); + mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mDozeScrimController = dozeScrimController; mKeyguardViewMediator = keyguardViewMediator; mScrimController = scrimController; @@ -214,7 +214,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { // notifications would light up first, creating an unpleasant animation. // Defer changing the screen brightness by forcing doze brightness on our window // until the clock and the notifications are faded out. - mStatusBarWindowManager.setForceDozeBrightness(true); + mStatusBarWindowController.setForceDozeBrightness(true); } // During wake and unlock, we need to draw black before waking up to avoid abrupt // brightness changes due to display state transitions. @@ -269,7 +269,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM"); mUpdateMonitor.awakenFromDream(); } - mStatusBarWindowManager.setStatusBarFocusable(false); + mStatusBarWindowController.setStatusBarFocusable(false); if (delayWakeUp) { mHandler.postDelayed(wakeUp, 50); } else { @@ -384,7 +384,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { mHandler.postDelayed(new Runnable() { @Override public void run() { - mStatusBarWindowManager.setForceDozeBrightness(false); + mStatusBarWindowController.setForceDozeBrightness(false); } }, StatusBar.FADE_KEYGUARD_DURATION_PULSING); } @@ -395,7 +395,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { private void resetMode() { mMode = MODE_NONE; - mStatusBarWindowManager.setForceDozeBrightness(false); + mStatusBarWindowController.setForceDozeBrightness(false); if (mStatusBar.getNavigationBarView() != null) { mStatusBar.getNavigationBarView().setWakeAndUnlocking(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index f48c3f5f5594..587b40d926d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -163,12 +163,16 @@ public class ButtonDispatcher { } public void setAlpha(float alpha, boolean animate) { + setAlpha(alpha, animate, (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT); + } + + public void setAlpha(float alpha, boolean animate, long duration) { if (animate) { if (mFadeAnimator != null) { mFadeAnimator.cancel(); } mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha); - mFadeAnimator.setDuration(getAlpha() < alpha? FADE_DURATION_IN : FADE_DURATION_OUT); + mFadeAnimator.setDuration(duration); mFadeAnimator.setInterpolator(getAlpha() < alpha ? ALPHA_IN : ALPHA_OUT); mFadeAnimator.addListener(mFadeListener); mFadeAnimator.addUpdateListener(mAlphaListener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java deleted file mode 100644 index 7ddca1756070..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java +++ /dev/null @@ -1,117 +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 com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.os.LocaleList; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; - -import com.android.systemui.ConfigurationChangedReceiver; -import com.android.systemui.statusbar.policy.ConfigurationController; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class ConfigurationControllerImpl implements ConfigurationController, - ConfigurationChangedReceiver { - - private final ArrayList<ConfigurationListener> mListeners = new ArrayList<>(); - private final Configuration mLastConfig = new Configuration(); - private int mDensity; - private float mFontScale; - private boolean mInCarMode; - private int mUiMode; - private LocaleList mLocaleList; - - public ConfigurationControllerImpl(Context context) { - Configuration currentConfig = context.getResources().getConfiguration(); - mFontScale = currentConfig.fontScale; - mDensity = currentConfig.densityDpi; - mInCarMode = (currentConfig.uiMode & Configuration.UI_MODE_TYPE_MASK) - == Configuration.UI_MODE_TYPE_CAR; - mUiMode = currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK; - mLocaleList = currentConfig.getLocales(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Avoid concurrent modification exception - ArrayList<ConfigurationListener> listeners = new ArrayList<>(mListeners); - - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onConfigChanged(newConfig); - } - }); - final float fontScale = newConfig.fontScale; - final int density = newConfig.densityDpi; - int uiMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK; - boolean uiModeChanged = uiMode != mUiMode; - if (density != mDensity || fontScale != mFontScale - || (mInCarMode && uiModeChanged)) { - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onDensityOrFontScaleChanged(); - } - }); - mDensity = density; - mFontScale = fontScale; - } - - final LocaleList localeList = newConfig.getLocales(); - if (!localeList.equals(mLocaleList)) { - mLocaleList = localeList; - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onLocaleListChanged(); - } - }); - } - - if (uiModeChanged) { - mUiMode = uiMode; - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onUiModeChanged(); - } - }); - } - - if ((mLastConfig.updateFrom(newConfig) & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onOverlayChanged(); - } - }); - } - } - - @Override - public void addCallback(ConfigurationListener listener) { - mListeners.add(listener); - listener.onDensityOrFontScaleChanged(); - } - - @Override - public void removeCallback(ConfigurationListener listener) { - mListeners.remove(listener); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt new file mode 100644 index 000000000000..81b596c0345e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt @@ -0,0 +1,117 @@ +/* + * 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.phone + +import android.content.Context +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.os.LocaleList + +import com.android.systemui.ConfigurationChangedReceiver +import com.android.systemui.statusbar.policy.ConfigurationController + +import java.util.ArrayList + +class ConfigurationControllerImpl(context: Context) + : ConfigurationController, ConfigurationChangedReceiver { + + private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList() + private val lastConfig = Configuration() + private var density: Int = 0 + private var fontScale: Float = 0.toFloat() + private val inCarMode: Boolean + private var uiMode: Int = 0 + private var localeList: LocaleList? = null + + init { + val currentConfig = context.resources.configuration + fontScale = currentConfig.fontScale + density = currentConfig.densityDpi + inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK == + Configuration.UI_MODE_TYPE_CAR + uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK + localeList = currentConfig.locales + } + + override fun notifyThemeChanged() { + val listeners = ArrayList(listeners) + + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onThemeChanged() + } + } + + override fun onConfigurationChanged(newConfig: Configuration) { + // Avoid concurrent modification exception + val listeners = ArrayList(listeners) + + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onConfigChanged(newConfig) + } + val fontScale = newConfig.fontScale + val density = newConfig.densityDpi + val uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK + val uiModeChanged = uiMode != this.uiMode + if (density != this.density || fontScale != this.fontScale || + inCarMode && uiModeChanged) { + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onDensityOrFontScaleChanged() + } + this.density = density + this.fontScale = fontScale + } + + val localeList = newConfig.locales + if (localeList != this.localeList) { + this.localeList = localeList + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onLocaleListChanged() + } + } + + if (uiModeChanged) { + this.uiMode = uiMode + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onUiModeChanged() + } + } + + if (lastConfig.updateFrom(newConfig) and ActivityInfo.CONFIG_ASSETS_PATHS != 0) { + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onOverlayChanged() + } + } + } + + override fun addCallback(listener: ConfigurationController.ConfigurationListener) { + listeners.add(listener) + listener.onDensityOrFontScaleChanged() + } + + override fun removeCallback(listener: ConfigurationController.ConfigurationListener) { + listeners.remove(listener) + } +} + +// This could be done with a Collection.filter and Collection.forEach, but Collection.filter +// creates a new array to store them in and we really don't need that here, so this provides +// a little more optimized inline version. +inline fun <T> Collection<T>.filterForEach(f: (T) -> Boolean, execute: (T) -> Unit) { + forEach { + if (f.invoke(it)) { + execute.invoke(it) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 81066f3e3610..6150c2f29391 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -31,12 +31,15 @@ import android.view.Gravity; import android.view.View; import android.view.ViewTreeObserver; +import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.ScreenDecorations; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -76,6 +79,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private boolean mIsObserving; private int mStatusBarState; + private final StateListener mStateListener = this::setStatusBarState; + private AnimationStateHandler mAnimationStateHandler; + private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() { private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>(); @@ -118,6 +124,15 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, updateTouchableRegionListener(); } }); + Dependency.get(StatusBarStateController.class).addListener(mStateListener); + } + + public void setAnimationStateHandler(AnimationStateHandler handler) { + mAnimationStateHandler = handler; + } + + public void destroy() { + Dependency.get(StatusBarStateController.class).removeListener(mStateListener); } private void initResources() { @@ -199,7 +214,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, /** * Set the current state of the statusbar. */ - public void setStatusBarState(int statusBarState) { + private void setStatusBarState(int statusBarState) { mStatusBarState = statusBarState; } @@ -340,7 +355,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @Override public void onReorderingAllowed() { - mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false); + mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false); for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) { if (contains(entry.key)) { // Maybe the heads-up was removed already @@ -348,7 +363,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } } mEntriesToRemoveWhenReorderingAllowed.clear(); - mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true); + mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -374,7 +389,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @Override protected void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) { super.dumpInternal(fd, pw, args); - pw.print(" mStatusBarState="); pw.println(mStatusBarState); + pw.print(" mBarState="); pw.println(mStatusBarState); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -484,4 +499,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } } } + + public interface AnimationStateHandler { + void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 20ea27a3f9c9..5630da6662e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -447,8 +447,8 @@ public class KeyguardStatusBarView extends RelativeLayout R.color.light_mode_icon_color_single_tone); float intensity = textColor == Color.WHITE ? 0 : 1; mCarrierLabel.setTextColor(iconColor); - mBatteryView.setFillColor(iconColor); mIconManager.setTint(iconColor); + mBatteryView.setColorsFromContext(mContext); Rect tintArea = new Rect(0, 0, 0, 0); applyDarkness(R.id.battery, tintArea, intensity, iconColor); 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 40c8fde3f845..b84ee037b9fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -195,8 +195,14 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @Override public void onBackButtonAlphaChanged(float alpha, boolean animate) { final ButtonDispatcher backButton = mNavigationBarView.getBackButton(); - backButton.setVisibility(alpha > 0 ? View.VISIBLE : View.INVISIBLE); - backButton.setAlpha(alpha, animate); + if (QuickStepController.shouldhideBackButton()) { + // If property was changed to hide/show back button, going home will trigger + // launcher to to change the back button alpha to reflect property change + backButton.setVisibility(View.GONE); + } else { + backButton.setVisibility(alpha > 0 ? View.VISIBLE : View.INVISIBLE); + backButton.setAlpha(alpha, animate); + } } }; 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 3e41cd2b39cc..1892d37c62d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -123,9 +123,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav private Rect mTmpRect = new Rect(); private KeyButtonDrawable mBackIcon; - private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon; - private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon; - private KeyButtonDrawable mHomeDefaultIcon, mHomeCarModeIcon; + private KeyButtonDrawable mHomeDefaultIcon; + private KeyButtonDrawable mBackCarModeIcon; + private KeyButtonDrawable mHomeCarModeIcon; private KeyButtonDrawable mRecentIcon; private KeyButtonDrawable mDockedIcon; private KeyButtonDrawable mImeIcon; @@ -461,16 +461,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav && ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0); } - // TODO(b/80003212): change car mode icons to vector icons. private void updateCarModeIcons(Context ctx) { - mBackCarModeIcon = getDrawable(ctx, - R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode); - mBackLandCarModeIcon = mBackCarModeIcon; - mBackAltCarModeIcon = getDrawable(ctx, - R.drawable.ic_sysbar_back_ime_carmode, R.drawable.ic_sysbar_back_ime_carmode); - mBackAltLandCarModeIcon = mBackAltCarModeIcon; - mHomeCarModeIcon = getDrawable(ctx, - R.drawable.ic_sysbar_home_carmode, R.drawable.ic_sysbar_home_carmode); + mBackCarModeIcon = getDrawable(ctx, R.drawable.ic_sysbar_back_carmode); + mHomeCarModeIcon = getDrawable(ctx, R.drawable.ic_sysbar_home_carmode); } private void reloadNavIcons() { @@ -575,11 +568,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav darkContext.getDrawable(icon), hasShadow); } - private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon, - @DrawableRes int darkIcon) { - // Legacy image icons using separate light and dark images will not support shadows - return KeyButtonDrawable.create(ctx, ctx.getDrawable(lightIcon), - ctx.getDrawable(darkIcon), false /* hasShadow */); + private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon) { + // Legacy image icons using a single image will not support shadows + return KeyButtonDrawable.create(ctx, ctx.getDrawable(icon), null, false /* hasShadow */); } private TintedKeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon, @@ -594,16 +585,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav super.setLayoutDirection(layoutDirection); } - private KeyButtonDrawable getBackIconWithAlt(boolean carMode, boolean landscape) { - return landscape - ? carMode ? mBackAltLandCarModeIcon : mBackIcon - : carMode ? mBackAltCarModeIcon : mBackIcon; - } - - private KeyButtonDrawable getBackIcon(boolean carMode, boolean landscape) { - return landscape - ? carMode ? mBackLandCarModeIcon : mBackIcon - : carMode ? mBackCarModeIcon : mBackIcon; + private KeyButtonDrawable getBackIcon(boolean carMode) { + return carMode ? mBackCarModeIcon : mBackIcon; } public void setNavigationIconHints(int hints) { @@ -643,12 +626,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav // to recent icon is not required. final boolean useAltBack = (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; - KeyButtonDrawable backIcon = useAltBack - ? getBackIconWithAlt(mUseCarModeUi, mVertical) - : getBackIcon(mUseCarModeUi, mVertical); + KeyButtonDrawable backIcon = getBackIcon(mUseCarModeUi); + orientBackButton(backIcon); KeyButtonDrawable homeIcon = mUseCarModeUi ? mHomeCarModeIcon : mHomeDefaultIcon; if (!mUseCarModeUi) { - orientBackButton(backIcon); orientHomeButton(homeIcon); } getHomeButton().setImageDrawable(homeIcon); @@ -682,7 +663,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav // Always disable recents when alternate car mode UI is active. boolean disableRecent = mUseCarModeUi || !isOverviewEnabled(); - boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack; + boolean disableBack = QuickStepController.shouldhideBackButton() + || (((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack); // When screen pinning, don't hide back and home when connected service or back and // recents buttons when disconnected from launcher service in screen pinning mode, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java index 214dda2b60b7..9c9b929ab7bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java @@ -60,7 +60,7 @@ public class NoisyVelocityTracker implements VelocityTrackerInterface { if (mEventBuf.size() == MAX_EVENTS) { mEventBuf.remove(); } - mEventBuf.add(new MotionEventCopy(event.getX(), event.getY(), event.getEventTime())); + mEventBuf.add(new MotionEventCopy(event.getRawX(), event.getRawY(), event.getEventTime())); } public void computeCurrentVelocity(int units) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index c27ccea30963..5fe362fc4d10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -22,9 +22,12 @@ import android.service.notification.StatusBarNotification; import androidx.annotation.Nullable; import android.util.Log; +import com.android.systemui.Dependency; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -52,6 +55,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { private boolean mIsUpdatingUnchangedGroup; private HashMap<String, NotificationData.Entry> mPendingNotifications; + private final StateListener mStateListener = this::setStatusBarState; + + public NotificationGroupManager() { + Dependency.get(StatusBarStateController.class).addListener(mStateListener); + } + public void setOnGroupChangeListener(OnGroupChangeListener listener) { mListener = listener; } @@ -357,10 +366,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { return group != null && group.suppressed; } - public void setStatusBarState(int newState) { - if (mBarState == newState) { - return; - } + private void setStatusBarState(int newState) { mBarState = newState; if (mBarState == StatusBarState.KEYGUARD) { collapseAllGroups(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index cb3a0d7c3647..b19f57d0dc93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import androidx.collection.ArrayMap; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.internal.statusbar.StatusBarIcon; @@ -45,7 +46,7 @@ public class NotificationIconAreaController implements DarkReceiver { private NotificationIconContainer mNotificationIcons; private NotificationIconContainer mShelfIcons; private final Rect mTintArea = new Rect(); - private NotificationStackScrollLayout mNotificationScrollLayout; + private ViewGroup mNotificationScrollLayout; private Context mContext; private boolean mFullyDark; private boolean mHasShelfIconsWhenFullyDark; @@ -71,8 +72,7 @@ public class NotificationIconAreaController implements DarkReceiver { LayoutInflater layoutInflater = LayoutInflater.from(context); mNotificationIconArea = inflateIconArea(layoutInflater); - mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById( - R.id.notificationIcons); + mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons); mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 747696376f8f..33ddfde845a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -16,7 +16,8 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator + .ExpandAnimationParameters; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -32,6 +33,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; @@ -54,29 +56,37 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.plugins.qs.QS; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.AnimatableProperty; +import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.PropertyAnimator; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -88,7 +98,8 @@ public class NotificationPanelView extends PanelView implements ExpandableView.OnHeightChangedListener, View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener, - OnHeadsUpChangedListener, QS.HeightListener { + OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback, + ConfigurationController.ConfigurationListener { private static final boolean DEBUG = false; @@ -175,7 +186,7 @@ public class NotificationPanelView extends PanelView implements private boolean mKeyguardShowing; private boolean mDozing; private boolean mDozingOnDown; - protected int mStatusBarState; + protected int mBarState; private float mInitialHeightOnTouch; private float mInitialTouchX; private float mInitialTouchY; @@ -311,6 +322,10 @@ public class NotificationPanelView extends PanelView implements .setDuration(200) .setAnimationFinishListener(mAnimatorListenerAdapter) .setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_IN); + private final NotificationEntryManager mEntryManager = + Dependency.get(NotificationEntryManager.class); + + private final StateListener mListener = this::setBarState; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -323,7 +338,7 @@ public class NotificationPanelView extends PanelView implements setPanelAlpha(255, false /* animate */); } - public void setStatusBar(StatusBar bar) { + private void setStatusBar(StatusBar bar) { mStatusBar = bar; mKeyguardBottomArea.setStatusBar(mStatusBar); } @@ -353,12 +368,18 @@ public class NotificationPanelView extends PanelView implements protected void onAttachedToWindow() { super.onAttachedToWindow(); FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener); + Dependency.get(StatusBarStateController.class).addListener(mListener); + Dependency.get(ZenModeController.class).addCallback(this); + Dependency.get(ConfigurationController.class).addCallback(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener); + Dependency.get(StatusBarStateController.class).removeListener(mListener); + Dependency.get(ZenModeController.class).removeCallback(this); + Dependency.get(ConfigurationController.class).removeCallback(this); } @Override @@ -405,7 +426,15 @@ public class NotificationPanelView extends PanelView implements } } + @Override + public void onDensityOrFontScaleChanged() { + updateShowEmptyShadeView(); + } + + @Override public void onThemeChanged() { + updateShowEmptyShadeView(); + // Re-inflate the status view group. int index = indexOfChild(mKeyguardStatusView); removeView(mKeyguardStatusView); @@ -426,8 +455,8 @@ public class NotificationPanelView extends PanelView implements initBottomArea(); setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount); - setKeyguardStatusViewVisibility(mStatusBarState, false, false); - setKeyguardBottomAreaVisibility(mStatusBarState, false); + setKeyguardStatusViewVisibility(mBarState, false, false); + setKeyguardBottomAreaVisibility(mBarState, false); } private void initBottomArea() { @@ -525,7 +554,7 @@ public class NotificationPanelView extends PanelView implements boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); boolean animateClock = animate || mAnimateNextPositionUpdate; int stackScrollerPadding; - if (mStatusBarState != StatusBarState.KEYGUARD) { + if (mBarState != StatusBarState.KEYGUARD) { stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight + mQsNotificationTopPadding; } else { @@ -581,8 +610,8 @@ public class NotificationPanelView extends PanelView implements continue; } ExpandableNotificationRow row = (ExpandableNotificationRow) child; - boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup( - row.getStatusBarNotification()); + boolean suppressedSummary = mGroupManager != null + && mGroupManager.isSummaryOfSuppressedGroup(row.getStatusBarNotification()); if (suppressedSummary) { continue; } @@ -853,7 +882,7 @@ public class NotificationPanelView extends PanelView implements private void logQsSwipeDown(float y) { float vel = getCurrentQSVelocity(); - final int gesture = mStatusBarState == StatusBarState.KEYGUARD + final int gesture = mBarState == StatusBarState.KEYGUARD ? MetricsEvent.ACTION_LS_QS : MetricsEvent.ACTION_SHADE_QS_PULL; mLockscreenGestureLogger.write(gesture, @@ -906,7 +935,7 @@ public class NotificationPanelView extends PanelView implements boolean handled = false; if ((!mIsExpanding || mHintAnimationRunning) && !mQsExpanded - && mStatusBar.getBarState() != StatusBarState.SHADE + && mBarState != StatusBarState.SHADE && !mDozing) { handled |= mAffordanceHelper.onTouchEvent(event); } @@ -930,7 +959,7 @@ public class NotificationPanelView extends PanelView implements private boolean handleQsTouch(MotionEvent event) { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f - && mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded + && mBarState != StatusBarState.KEYGUARD && !mQsExpanded && mQsExpansionEnabled) { // Down in the empty area while fully expanded - go to QS. @@ -1024,7 +1053,7 @@ public class NotificationPanelView extends PanelView implements @Override protected boolean hasConflictingGestures() { - return mStatusBar.getBarState() != StatusBarState.SHADE; + return mBarState != StatusBarState.SHADE; } @Override @@ -1162,14 +1191,15 @@ public class NotificationPanelView extends PanelView implements } } - public void setBarState(int statusBarState, boolean keyguardFadingAway, - boolean goingToFullShade) { - int oldState = mStatusBarState; + private void setBarState(int statusBarState) { + boolean goingToFullShade = mStatusBarStateController.goingToFullShade(); + boolean keyguardFadingAway = mKeyguardMonitor.isKeyguardFadingAway(); + int oldState = mBarState; boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD; setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade); setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade); - mStatusBarState = statusBarState; + mBarState = statusBarState; mKeyguardShowing = keyguardShowing; if (mQs != null) { mQs.setKeyguardShowing(mKeyguardShowing); @@ -1178,8 +1208,8 @@ public class NotificationPanelView extends PanelView implements if (oldState == StatusBarState.KEYGUARD && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) { animateKeyguardStatusBarOut(); - long delay = mStatusBarState == StatusBarState.SHADE_LOCKED - ? 0 : mStatusBar.calculateGoingToFullShadeDelay(); + long delay = mBarState == StatusBarState.SHADE_LOCKED + ? 0 : mKeyguardMonitor.calculateGoingToFullShadeDelay(); mQs.animateHeaderSlidingIn(delay); } else if (oldState == StatusBarState.SHADE_LOCKED && statusBarState == StatusBarState.KEYGUARD) { @@ -1188,7 +1218,7 @@ public class NotificationPanelView extends PanelView implements } else { mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); - if (keyguardShowing && oldState != mStatusBarState) { + if (keyguardShowing && oldState != mBarState) { mKeyguardBottomArea.onKeyguardShowingChanged(); if (mQs != null) { mQs.hideImmediately(); @@ -1237,11 +1267,11 @@ public class NotificationPanelView extends PanelView implements private void animateKeyguardStatusBarOut() { ValueAnimator anim = ValueAnimator.ofFloat(mKeyguardStatusBar.getAlpha(), 0f); anim.addUpdateListener(mStatusBarAnimateAlphaListener); - anim.setStartDelay(mStatusBar.isKeyguardFadingAway() - ? mStatusBar.getKeyguardFadingAwayDelay() + anim.setStartDelay(mKeyguardMonitor.isKeyguardFadingAway() + ? mKeyguardMonitor.getKeyguardFadingAwayDelay() : 0); - anim.setDuration(mStatusBar.isKeyguardFadingAway() - ? mStatusBar.getKeyguardFadingAwayDuration() / 2 + anim.setDuration(mKeyguardMonitor.isKeyguardFadingAway() + ? mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2 : StackStateAnimator.ANIMATION_DURATION_STANDARD); anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); anim.addListener(new AnimatorListenerAdapter() { @@ -1285,8 +1315,8 @@ public class NotificationPanelView extends PanelView implements if (goingToFullShade) { mKeyguardBottomArea.animate() .alpha(0f) - .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay()) - .setDuration(mStatusBar.getKeyguardFadingAwayDuration() / 2) + .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay()) + .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2) .setInterpolator(Interpolators.ALPHA_OUT) .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable) .start(); @@ -1304,7 +1334,7 @@ public class NotificationPanelView extends PanelView implements boolean goingToFullShade) { mKeyguardStatusView.animate().cancel(); mKeyguardStatusViewAnimating = false; - if ((!keyguardFadingAway && mStatusBarState == StatusBarState.KEYGUARD + if ((!keyguardFadingAway && mBarState == StatusBarState.KEYGUARD && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) { mKeyguardStatusViewAnimating = true; mKeyguardStatusView.animate() @@ -1315,11 +1345,11 @@ public class NotificationPanelView extends PanelView implements .withEndAction(mAnimateKeyguardStatusViewGoneEndRunnable); if (keyguardFadingAway) { mKeyguardStatusView.animate() - .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay()) - .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2) + .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay()) + .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()/2) .start(); } - } else if (mStatusBarState == StatusBarState.SHADE_LOCKED + } else if (mBarState == StatusBarState.SHADE_LOCKED && statusBarState == StatusBarState.KEYGUARD) { mKeyguardStatusView.setVisibility(View.VISIBLE); mKeyguardStatusViewAnimating = true; @@ -1354,10 +1384,10 @@ public class NotificationPanelView extends PanelView implements private void updateQsState() { mNotificationStackScroller.setQsExpanded(mQsExpanded); mNotificationStackScroller.setScrollingEnabled( - mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded + mBarState != StatusBarState.KEYGUARD && (!mQsExpanded || mQsExpansionFromOverscroll)); updateEmptyShadeView(); - mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded + mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling && mQsScrimEnabled ? View.VISIBLE : View.INVISIBLE); @@ -1380,11 +1410,11 @@ public class NotificationPanelView extends PanelView implements updateQsExpansion(); requestScrollerTopPaddingUpdate(false /* animate */); updateHeaderKeyguardAlpha(); - if (mStatusBarState == StatusBarState.SHADE_LOCKED - || mStatusBarState == StatusBarState.KEYGUARD) { + if (mBarState == StatusBarState.SHADE_LOCKED + || mBarState == StatusBarState.KEYGUARD) { updateKeyguardBottomAreaAlpha(); } - if (mStatusBarState == StatusBarState.SHADE && mQsExpanded + if (mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling && mQsScrimEnabled) { mQsNavbarScrim.setAlpha(getQsExpansionFraction()); } @@ -1416,7 +1446,7 @@ public class NotificationPanelView extends PanelView implements // Upon initialisation when we are not layouted yet we don't want to announce that we // are fully expanded, hence the != 0.0f check. return getContext().getString(R.string.accessibility_desc_quick_settings); - } else if (mStatusBarState == StatusBarState.KEYGUARD) { + } else if (mBarState == StatusBarState.KEYGUARD) { return getContext().getString(R.string.accessibility_desc_lock_screen); } else { return getContext().getString(R.string.accessibility_desc_notification_shade); @@ -1434,7 +1464,7 @@ public class NotificationPanelView extends PanelView implements // for a nice motion. int maxNotificationPadding = mClockPositionResult.stackScrollerPadding; int maxQsPadding = mQsMaxExpansionHeight + mQsNotificationTopPadding; - int max = mStatusBarState == StatusBarState.KEYGUARD + int max = mBarState == StatusBarState.KEYGUARD ? Math.max(maxNotificationPadding, maxQsPadding) : maxQsPadding; return (int) interpolate(getExpandedFraction(), @@ -1577,7 +1607,7 @@ public class NotificationPanelView extends PanelView implements @Override protected boolean isScrolledToBottom() { if (!isInSettings()) { - return mStatusBar.getBarState() == StatusBarState.KEYGUARD + return mBarState == StatusBarState.KEYGUARD || mNotificationStackScroller.isScrolledToBottom(); } else { return true; @@ -1587,7 +1617,7 @@ public class NotificationPanelView extends PanelView implements @Override protected int getMaxPanelHeight() { int min = mStatusBarMinHeight; - if (mStatusBar.getBarState() != StatusBarState.KEYGUARD + if (mBarState != StatusBarState.KEYGUARD && mNotificationStackScroller.getNotGoneChildCount() == 0) { int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount()); min = Math.max(min, minHeight); @@ -1667,7 +1697,7 @@ public class NotificationPanelView extends PanelView implements int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin; maxHeight += mNotificationStackScroller.getTopPaddingOverflow(); - if (mStatusBarState == StatusBarState.KEYGUARD) { + if (mBarState == StatusBarState.KEYGUARD) { int minKeyguardPanelBottom = mClockPositionAlgorithm.getExpandedClockPosition() + mKeyguardStatusView.getHeight() + mNotificationStackScroller.getIntrinsicContentHeight(); @@ -1700,7 +1730,7 @@ public class NotificationPanelView extends PanelView implements maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue(); } float totalHeight = Math.max( - maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD + maxQsHeight, mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding : 0) + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow(); if (totalHeight > mNotificationStackScroller.getHeight()) { @@ -1739,8 +1769,8 @@ public class NotificationPanelView extends PanelView implements } private void updateUnlockIcon() { - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD - || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) { + if (mBarState == StatusBarState.KEYGUARD + || mBarState == StatusBarState.SHADE_LOCKED) { boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance; KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); if (active && !mUnlockIconActive && mTracking) { @@ -1761,14 +1791,14 @@ public class NotificationPanelView extends PanelView implements * Hides the header when notifications are colliding with it. */ private void updateHeader() { - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (mBarState == StatusBarState.KEYGUARD) { updateHeaderKeyguardAlpha(); } updateQsExpansion(); } protected float getHeaderTranslation() { - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (mBarState == StatusBarState.KEYGUARD) { return 0; } float translation = MathUtils.lerp(-mQsMinExpansionHeight, 0, @@ -1783,7 +1813,7 @@ public class NotificationPanelView extends PanelView implements */ private float getKeyguardContentsAlpha() { float alpha; - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (mBarState == StatusBarState.KEYGUARD) { // When on Keyguard, we hide the header as soon as the top card of the notification // stack scroller is close enough (collision distance) to the bottom of the header. @@ -1915,7 +1945,7 @@ public class NotificationPanelView extends PanelView implements if (mConflictingQsExpansionGesture || mQsExpandImmediate) { return; } - if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { + if (mBarState != StatusBarState.KEYGUARD) { mNotificationStackScroller.setOnHeightChangedListener(null); if (isPixels) { mNotificationStackScroller.setOverScrolledPixels( @@ -1936,8 +1966,8 @@ public class NotificationPanelView extends PanelView implements mQsExpandImmediate = true; mNotificationStackScroller.setShouldShowShelfOnly(true); } - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD - || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) { + if (mBarState == StatusBarState.KEYGUARD + || mBarState == StatusBarState.SHADE_LOCKED) { mAffordanceHelper.animateHideLeftRightIcon(); } mNotificationStackScroller.onPanelTrackingStarted(); @@ -1952,14 +1982,14 @@ public class NotificationPanelView extends PanelView implements 0.0f, true /* onTop */, true /* animate */); } mNotificationStackScroller.onPanelTrackingStopped(); - if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD - || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) { + if (expand && (mBarState == StatusBarState.KEYGUARD + || mBarState == StatusBarState.SHADE_LOCKED)) { if (!mHintAnimationRunning) { mAffordanceHelper.reset(true); } } - if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD - || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) { + if (!expand && (mBarState == StatusBarState.KEYGUARD + || mBarState == StatusBarState.SHADE_LOCKED)) { KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon(); lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null); lockIcon.setImageScale(2.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN); @@ -2233,7 +2263,7 @@ public class NotificationPanelView extends PanelView implements @Override public boolean needsAntiFalsing() { - return mStatusBarState == StatusBarState.KEYGUARD; + return mBarState == StatusBarState.KEYGUARD; } @Override @@ -2247,7 +2277,7 @@ public class NotificationPanelView extends PanelView implements @Override protected boolean shouldUseDismissingAnimation() { - return mStatusBarState != StatusBarState.SHADE + return mBarState != StatusBarState.SHADE && (!mStatusBar.isKeyguardCurrentlySecure() || !isTracking()); } @@ -2340,7 +2370,6 @@ public class NotificationPanelView extends PanelView implements } private void updateEmptyShadeView() { - // Hide "No notifications" in QS. mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded); } @@ -2368,7 +2397,7 @@ public class NotificationPanelView extends PanelView implements @Override protected boolean onMiddleClicked() { - switch (mStatusBar.getBarState()) { + switch (mBarState) { case StatusBarState.KEYGUARD: if (!mDozingOnDown) { mLockscreenGestureLogger.write( @@ -2587,7 +2616,7 @@ public class NotificationPanelView extends PanelView implements } private boolean isOnKeyguard() { - return mStatusBar.getBarState() == StatusBarState.KEYGUARD; + return mBarState == StatusBarState.KEYGUARD; } public void setPanelScrimMinFraction(float minFraction) { @@ -2711,7 +2740,7 @@ public class NotificationPanelView extends PanelView implements return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); } - public void setGroupManager(NotificationGroupManager groupManager) { + private void setGroupManager(NotificationGroupManager groupManager) { mGroupManager = groupManager; } @@ -2761,19 +2790,22 @@ public class NotificationPanelView extends PanelView implements }; @Override - public void setTouchDisabled(boolean disabled) { - super.setTouchDisabled(disabled); + public void setTouchAndAnimationDisabled(boolean disabled) { + super.setTouchAndAnimationDisabled(disabled); if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) { mAffordanceHelper.reset(false /* animate */); } + mNotificationStackScroller.setAnimationsEnabled(!disabled); } - public void setDozing(boolean dozing, boolean animate) { + public void setDozing(boolean dozing, boolean animate, + PointF wakeUpTouchLocation) { + mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation); if (dozing == mDozing) return; mDozing = dozing; - if (mStatusBarState == StatusBarState.KEYGUARD - || mStatusBarState == StatusBarState.SHADE_LOCKED) { + if (mBarState == StatusBarState.KEYGUARD + || mBarState == StatusBarState.SHADE_LOCKED) { updateDozingVisibilities(animate); } @@ -2902,7 +2934,7 @@ public class NotificationPanelView extends PanelView implements * security view of the bouncer. */ public void onBouncerPreHideAnimation() { - setKeyguardStatusViewVisibility(mStatusBarState, true /* keyguardFadingAway */, + setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */, false /* goingToFullShade */); } @@ -2913,4 +2945,83 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusBar.dump(fd, pw, args); } } + + public boolean hasActiveClearableNotifications() { + return mNotificationStackScroller.hasActiveClearableNotifications(); + } + + @Override + public void onZenChanged(int zen) { + updateShowEmptyShadeView(); + } + + private void updateShowEmptyShadeView() { + boolean showEmptyShadeView = + mBarState != StatusBarState.KEYGUARD && + mEntryManager.getNotificationData().getActiveNotifications().size() == 0; + showEmptyShadeView(showEmptyShadeView); + } + + public RemoteInputController.Delegate createRemoteInputDelegate() { + return mNotificationStackScroller.createDelegate(); + } + + public void updateNotificationViews() { + mNotificationStackScroller.updateSpeedBumpIndex(); + mNotificationStackScroller.updateFooter(); + updateShowEmptyShadeView(); + } + + public void onUpdateRowStates() { + mNotificationStackScroller.onUpdateRowStates(); + } + + public boolean hasPulsingNotifications() { + return mNotificationStackScroller.hasPulsingNotifications(); + } + + public boolean isFullyDark() { + return mNotificationStackScroller.isFullyDark(); + } + + public ActivatableNotificationView getActivatedChild() { + return mNotificationStackScroller.getActivatedChild(); + } + + public void setActivatedChild(ActivatableNotificationView o) { + mNotificationStackScroller.setActivatedChild(o); + } + + public void setParentNotFullyVisible(boolean parent) { + mNotificationStackScroller.setParentNotFullyVisible(parent); + } + + public void runAfterAnimationFinished(Runnable r) { + mNotificationStackScroller.runAfterAnimationFinished(r); + } + + public void setScrollingEnabled(boolean b) { + mNotificationStackScroller.setScrollingEnabled(b); + } + + public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager, + NotificationShelf notificationShelf, + HeadsUpManagerPhone headsUpManager, + NotificationIconAreaController notificationIconAreaController, + ScrimController scrimController) { + setStatusBar(statusBar); + setGroupManager(mGroupManager); + mNotificationStackScroller.setNotificationPanel(this); + mNotificationStackScroller.setIconAreaController(notificationIconAreaController); + mNotificationStackScroller.setStatusBar(statusBar); + mNotificationStackScroller.setGroupManager(groupManager); + mNotificationStackScroller.setHeadsUpManager(headsUpManager); + mNotificationStackScroller.setShelf(notificationShelf); + mNotificationStackScroller.setScrimController(scrimController); + updateShowEmptyShadeView(); + } + + public void setDrawBackgroundAsSrc(boolean asSrc) { + mNotificationStackScroller.setDrawBackgroundAsSrc(asSrc); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 1f09835a8eb9..bef34f6b9125 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -45,7 +45,9 @@ import com.android.systemui.classifier.FalsingManager; import com.android.systemui.doze.DozeLog; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -138,6 +140,9 @@ public abstract class PanelView extends FrameLayout { private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; + protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); + protected final StatusBarStateController + mStatusBarStateController = Dependency.get(StatusBarStateController.class); protected void onExpandingFinished() { mBar.onExpandingFinished(); @@ -222,16 +227,10 @@ public abstract class PanelView extends FrameLayout { } private void trackMovement(MotionEvent event) { - // Add movement to velocity tracker using raw screen X and Y coordinates instead - // of window coordinates because the window frame may be moving at the same time. - float deltaX = event.getRawX() - event.getX(); - float deltaY = event.getRawY() - event.getY(); - event.offsetLocation(deltaX, deltaY); if (mVelocityTracker != null) mVelocityTracker.addMovement(event); - event.offsetLocation(-deltaX, -deltaY); } - public void setTouchDisabled(boolean disabled) { + public void setTouchAndAnimationDisabled(boolean disabled) { mTouchDisabled = disabled; if (mTouchDisabled) { cancelHeightAnimator(); @@ -341,7 +340,7 @@ public abstract class PanelView extends FrameLayout { } break; case MotionEvent.ACTION_POINTER_DOWN: - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { mMotionAborted = true; endMotionEvent(event, x, y, true /* forceCancel */); return false; @@ -474,7 +473,7 @@ public abstract class PanelView extends FrameLayout { mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch()); // Log collapse gesture if on lock screen. - if (!expand && mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (!expand && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { float displayDensity = mStatusBar.getDisplayDensity(); int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity); int velocityDp = (int) Math.abs(vel / displayDensity); @@ -489,7 +488,7 @@ public abstract class PanelView extends FrameLayout { mUpdateFlingVelocity = vel; } } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking - && !mStatusBar.isBouncerShowing() && !mStatusBar.isKeyguardFadingAway()) { + && !mStatusBar.isBouncerShowing() && !mKeyguardMonitor.isKeyguardFadingAway()) { long timePassed = SystemClock.uptimeMillis() - mDownTime; if (timePassed < ViewConfiguration.getLongPressTimeout()) { // Lets show the user that he can actually expand the panel @@ -603,7 +602,7 @@ public abstract class PanelView extends FrameLayout { } break; case MotionEvent.ACTION_POINTER_DOWN: - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { mMotionAborted = true; if (mVelocityTracker != null) { mVelocityTracker.recycle(); 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 a13bebdcdc0a..bd4d790a00b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java @@ -23,6 +23,7 @@ import static com.android.systemui.Interpolators.ALPHA_OUT; import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY; import static com.android.systemui.OverviewProxyService.TAG_OPS; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_DEAD_ZONE; +import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,15 +38,24 @@ import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.Shader; +import android.hardware.input.InputManager; import android.os.Handler; import android.os.RemoteException; +import android.os.SystemClock; +import android.os.SystemProperties; import android.util.FloatProperty; import android.util.Log; import android.util.Slog; +import android.view.HapticFeedbackConstants; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.ViewPropertyAnimator; import android.view.WindowManagerGlobal; import com.android.systemui.Dependency; +import com.android.systemui.Interpolators; import com.android.systemui.OverviewProxyService; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; @@ -64,10 +74,25 @@ public class QuickStepController implements GestureHelper { private static final float TRACK_SCALE = 0.95f; private static final float GRADIENT_WIDTH = .75f; + /** Experiment to swipe home button left to execute a back key press */ + private static final String PULL_HOME_GO_BACK_PROP = "persist.quickstepcontroller.homegoesback"; + private static final String HIDE_BACK_BUTTON_PROP = "persist.quickstepcontroller.hideback"; + private static final long BACK_BUTTON_FADE_OUT_ALPHA = 60; + private static final long BACK_BUTTON_FADE_IN_ALPHA = 150; + private static final long BACK_GESTURE_POLL_TIMEOUT = 1000; + + /** When the home-swipe-back gesture is disallowed, make it harder to pull */ + private static final float DISALLOW_GESTURE_DAMPING_FACTOR = 0.16f; + + /** When dragging the home button too far during back gesture, make it harder to pull */ + private static final float EXCEED_DRAG_HOME_DAMPING_FACTOR = 0.33f; + private NavigationBarView mNavigationBarView; private boolean mQuickScrubActive; private boolean mAllowGestureDetection; + private boolean mBackGestureActive; + private boolean mCanPerformBack; private boolean mQuickStepStarted; private boolean mNotificationsVisibleOnDown; private int mTouchDownX; @@ -81,6 +106,7 @@ public class QuickStepController implements GestureHelper { private RadialGradient mHighlight; private float mHighlightCenter; private AnimatorSet mTrackAnimator; + private ViewPropertyAnimator mHomeAnimator; private ButtonDispatcher mHitTarget; private View mCurrentNavigationBarView; private boolean mIsInScreenPinning; @@ -90,11 +116,20 @@ public class QuickStepController implements GestureHelper { private final OverviewProxyService mOverviewEventSender; private final int mTrackThickness; private final int mTrackEndPadding; + private final int mHomeBackGestureDragLimit; private final Context mContext; private final Matrix mTransformGlobalMatrix = new Matrix(); private final Matrix mTransformLocalMatrix = new Matrix(); private final Paint mTrackPaint = new Paint(); + public static boolean swipeHomeGoBackGestureEnabled() { + return SystemProperties.getBoolean(PULL_HOME_GO_BACK_PROP, false); + } + public static boolean shouldhideBackButton() { + return swipeHomeGoBackGestureEnabled() + && SystemProperties.getBoolean(HIDE_BACK_BUTTON_PROP, false); + } + private final FloatProperty<QuickStepController> mTrackAlphaProperty = new FloatProperty<QuickStepController>("TrackAlpha") { @Override @@ -148,18 +183,34 @@ public class QuickStepController implements GestureHelper { } }; + private final Runnable mExecuteBackRunnable = new Runnable() { + @Override + public void run() { + if (canPerformHomeBackGesture()) { + performBack(); + mHandler.postDelayed(this, BACK_GESTURE_POLL_TIMEOUT); + } + } + }; + public QuickStepController(Context context) { final Resources res = context.getResources(); mContext = context; 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); + mHomeBackGestureDragLimit = + res.getDimensionPixelSize(R.dimen.nav_home_back_gesture_drag_limit); mTrackPaint.setAntiAlias(true); mTrackPaint.setDither(true); } public void setComponents(NavigationBarView navigationBarView) { mNavigationBarView = navigationBarView; + + mNavigationBarView.getBackButton().setVisibility(shouldhideBackButton() + ? View.GONE + : View.VISIBLE); } /** @@ -218,8 +269,10 @@ public class QuickStepController implements GestureHelper { mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix); mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix); mQuickStepStarted = false; + mBackGestureActive = false; mAllowGestureDetection = true; mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed(); + mCanPerformBack = canPerformHomeBackGesture(); break; } case MotionEvent.ACTION_MOVE: { @@ -255,7 +308,7 @@ public class QuickStepController implements GestureHelper { } // Decide to start quickstep if dragging away from the navigation bar, otherwise in // the parallel direction, decide to start quickscrub. Only one may run. - if (!mQuickScrubActive && exceededSwipeUpTouchSlop) { + if (!mBackGestureActive && !mQuickScrubActive && exceededSwipeUpTouchSlop) { if (mNavigationBarView.isQuickStepSwipeUpEnabled() && !mNotificationsVisibleOnDown) { startQuickStep(event); @@ -275,10 +328,14 @@ public class QuickStepController implements GestureHelper { final boolean allowDrag = !mDragPositive ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown; float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1); - if (allowDrag) { + if (!mQuickScrubActive && !mBackGestureActive && exceededScrubTouchSlop) { // Passing the drag slop then touch slop will start quick step - if (!mQuickScrubActive && exceededScrubTouchSlop) { + if (allowDrag) { startQuickScrub(); + } else if (swipeHomeGoBackGestureEnabled() + && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME + && mDragPositive ? pos < touchDown : pos > touchDown) { + startBackGesture(); } } @@ -294,23 +351,41 @@ public class QuickStepController implements GestureHelper { } mHighlightCenter = x; mNavigationBarView.invalidate(); + } else if (mBackGestureActive) { + int diff = pos - touchDown; + // If dragging the incorrect direction after starting back gesture or unable + // to execute back functionality, then move home but dampen its distance + if (!mCanPerformBack || (mDragPositive ? diff > 0 : diff < 0)) { + diff *= DISALLOW_GESTURE_DAMPING_FACTOR; + } if (Math.abs(diff) > mHomeBackGestureDragLimit) { + // Once the user drags the home button past a certain limit, the distance + // will lessen as the home button dampens showing that it was pulled too far + float distanceAfterDragLimit = (Math.abs(diff) - mHomeBackGestureDragLimit) + * EXCEED_DRAG_HOME_DAMPING_FACTOR; + diff = (int)(distanceAfterDragLimit + mHomeBackGestureDragLimit); + if (mDragPositive) { + diff *= -1; + } + } + moveHomeButton(diff); } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: endQuickScrub(true /* animate */); + endBackGesture(); break; } if (shouldProxyEvents(action)) { proxyMotionEvents(event); } - return mQuickScrubActive || mQuickStepStarted || deadZoneConsumed; + return mBackGestureActive || mQuickScrubActive || mQuickStepStarted || deadZoneConsumed; } private boolean shouldProxyEvents(int action) { - if (!mQuickScrubActive && !mIsInScreenPinning) { + if (!mBackGestureActive && !mQuickScrubActive && !mIsInScreenPinning) { // Allow down, cancel and up events, move and other events are passed if notifications // are not showing and disabled gestures (such as long press) are not executed switch (action) { @@ -501,6 +576,42 @@ public class QuickStepController implements GestureHelper { } } + private void startBackGesture() { + if (!mBackGestureActive) { + mBackGestureActive = true; + mNavigationBarView.getHomeButton().abortCurrentGesture(); + if (mCanPerformBack) { + if (!shouldhideBackButton()) { + mNavigationBarView.getBackButton().setAlpha(0 /* alpha */, true /* animate */, + BACK_BUTTON_FADE_OUT_ALPHA); + } + performBack(); + } + mHandler.removeCallbacks(mExecuteBackRunnable); + mHandler.postDelayed(mExecuteBackRunnable, BACK_GESTURE_POLL_TIMEOUT); + } + } + + private void endBackGesture() { + if (mBackGestureActive) { + mHandler.removeCallbacks(mExecuteBackRunnable); + mHomeAnimator = mNavigationBarView.getHomeButton().getCurrentView() + .animate() + .setDuration(BACK_BUTTON_FADE_IN_ALPHA) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + if (mIsVertical) { + mHomeAnimator.translationY(0); + } else { + mHomeAnimator.translationX(0); + } + mHomeAnimator.start(); + if (!shouldhideBackButton()) { + mNavigationBarView.getBackButton().setAlpha( + mOverviewEventSender.getBackButtonAlpha(), true /* animate */); + } + } + } + private void animateEnd() { if (mTrackAnimator != null) { mTrackAnimator.cancel(); @@ -530,6 +641,19 @@ public class QuickStepController implements GestureHelper { updateHighlight(); } + private void moveHomeButton(float pos) { + if (mHomeAnimator != null) { + mHomeAnimator.cancel(); + mHomeAnimator = null; + } + final View homeButton = mNavigationBarView.getHomeButton().getCurrentView(); + if (mIsVertical) { + homeButton.setTranslationY(pos); + } else { + homeButton.setTranslationX(pos); + } + } + private void updateHighlight() { if (mTrackRect.isEmpty()) { return; @@ -548,6 +672,25 @@ public class QuickStepController implements GestureHelper { mTrackPaint.setShader(mHighlight); } + private boolean canPerformHomeBackGesture() { + return swipeHomeGoBackGestureEnabled() && mOverviewEventSender.getBackButtonAlpha() > 0; + } + + private void performBack() { + sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); + sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); + mNavigationBarView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); + } + + private void sendEvent(int action, int code) { + long when = SystemClock.uptimeMillis(); + final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */, + 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, + KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, + InputDevice.SOURCE_KEYBOARD); + InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + } + private boolean proxyMotionEvents(MotionEvent event) { final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy(); event.transform(mTransformGlobalMatrix); 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 3701eafeb5eb..a318e151d725 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -148,6 +148,7 @@ import com.android.systemui.ActivityStarterDelegate; import com.android.systemui.AutoReinflateContainer; import com.android.systemui.DemoMode; import com.android.systemui.Dependency; +import com.android.systemui.Dumpable; import com.android.systemui.EventLogTags; import com.android.systemui.Interpolators; import com.android.systemui.Prefs; @@ -185,15 +186,14 @@ 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; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.AppOpsListener; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; -import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyboardShortcuts; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -212,11 +212,12 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.ScrimView; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.BatteryController; @@ -247,13 +248,13 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; -import java.util.List; import java.util.Map; public class StatusBar extends SystemUI implements DemoMode, - DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener, + ActivityStarter, OnUnlockMethodChangedListener, OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback, - ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter { + ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter, + StatusBarStateController.StateListener { public static final boolean MULTIUSER_DEBUG = false; public static final boolean ENABLE_CHILD_NOTIFICATIONS @@ -370,7 +371,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarWindowView mStatusBarWindow; protected PhoneStatusBarView mStatusBarView; private int mStatusBarWindowState = WINDOW_STATE_SHOWING; - protected StatusBarWindowManager mStatusBarWindowManager; + protected StatusBarWindowController mStatusBarWindowController; protected UnlockMethodCache mUnlockMethodCache; private DozeServiceHost mDozeServiceHost = new DozeServiceHost(); private boolean mWakeUpComingFromTouch; @@ -389,14 +390,8 @@ public class StatusBar extends SystemUI implements DemoMode, // top bar private KeyguardStatusBarView mKeyguardStatusBar; - private boolean mLeaveOpenOnKeyguardHide; KeyguardIndicationController mKeyguardIndicationController; - // Keyguard is actually fading away now. - protected boolean mKeyguardFadingAway; - protected long mKeyguardFadingAwayDelay; - protected long mKeyguardFadingAwayDuration; - // RemoteInputView to be activated after unlock private View mPendingRemoteInputView; private View mPendingWorkRemoteInputView; @@ -429,12 +424,11 @@ public class StatusBar extends SystemUI implements DemoMode, private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; private final Rect mLastFullscreenStackBounds = new Rect(); private final Rect mLastDockedStackBounds = new Rect(); - private final Rect mTmpRect = new Rect(); // last value sent to window manager private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; - private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class); // XXX: gesture research private final GestureRecorder mGestureRec = DEBUG_GESTURES @@ -515,7 +509,7 @@ public class StatusBar extends SystemUI implements DemoMode, final boolean supportsAmbientMode = info != null && info.supportsAmbientMode(); - mStatusBarWindowManager.setWallpaperSupportsAmbientMode(supportsAmbientMode); + mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); } }; @@ -553,7 +547,7 @@ public class StatusBar extends SystemUI implements DemoMode, + "mStatusBarKeyguardViewManager was null"); return; } - if (mKeyguardFadingAway) { + if (mKeyguardMonitor.isKeyguardFadingAway()) { mStatusBarKeyguardViewManager.onKeyguardFadedAway(); } } @@ -575,10 +569,10 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mKeyguardRequested; private boolean mIsKeyguard; private LogMaker mStatusBarStateLog; - private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); + private final LockscreenGestureLogger mLockscreenGestureLogger = + Dependency.get(LockscreenGestureLogger.class); protected NotificationIconAreaController mNotificationIconAreaController; private boolean mReinflateNotificationsOnUserSwitched; - protected boolean mClearAllEnabled; @Nullable private View mAmbientIndicationContainer; private SysuiColorExtractor mColorExtractor; private ScreenLifecycle mScreenLifecycle; @@ -592,6 +586,8 @@ public class StatusBar extends SystemUI implements DemoMode, }; private boolean mNoAnimationOnNextBarModeChange; protected FalsingManager mFalsingManager; + private final StatusBarStateController + mStatusBarStateController = Dependency.get(StatusBarStateController.class); private final KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -645,6 +641,7 @@ public class StatusBar extends SystemUI implements DemoMode, mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); + mStatusBarStateController.addListener(this); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); @@ -656,7 +653,6 @@ public class StatusBar extends SystemUI implements DemoMode, R.bool.config_vibrateOnIconAnimation); mVibratorHelper = Dependency.get(VibratorHelper.class); mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src); - mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER)); putComponent(StatusBar.class, this); @@ -798,12 +794,13 @@ public class StatusBar extends SystemUI implements DemoMode, // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel); mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller); + NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller; mZenController.addCallback(this); mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow, this, mNotificationPanel, - mStackScroller); - mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener, + notifListContainer); + mGutsManager.setUpWithPresenter(this, mEntryManager, notifListContainer, mCheckSaveListener, key -> { try { mBarService.onNotificationSettingsViewed(key); @@ -811,9 +808,7 @@ public class StatusBar extends SystemUI implements DemoMode, // if we're here we're dead } }); - mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller); - mNotificationPanel.setStatusBar(this); - mNotificationPanel.setGroupManager(mGroupManager); + mNotificationLogger.setUpWithEntryManager(mEntryManager, notifListContainer); mAboveShelfObserver = new AboveShelfObserver(mStackScroller); mAboveShelfObserver.setListener(mStatusBarWindow.findViewById( R.id.notification_container_parent)); @@ -823,7 +818,7 @@ public class StatusBar extends SystemUI implements DemoMode, .createNotificationIconAreaController(context, this); inflateShelf(); mNotificationIconAreaController.setupShelf(mNotificationShelf); - mStackScroller.setIconAreaController(mNotificationIconAreaController); + Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); FragmentHostManager.get(mStatusBarWindow) .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { @@ -882,8 +877,8 @@ public class StatusBar extends SystemUI implements DemoMode, mGroupManager.setHeadsUpManager(mHeadsUpManager); putComponent(HeadsUpManager.class, mHeadsUpManager); - mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager); - mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller); + mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager); + mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, notifListContainer); if (MULTIUSER_DEBUG) { mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info); @@ -899,15 +894,6 @@ public class StatusBar extends SystemUI implements DemoMode, } catch (RemoteException ex) { // no window manager? good luck with that } - mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker()); - mStackScroller.setStatusBar(this); - mStackScroller.setGroupManager(mGroupManager); - mStackScroller.setHeadsUpManager(mHeadsUpManager); - mGroupManager.setOnGroupChangeListener(mStackScroller); - mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller); - - inflateEmptyShadeView(); - inflateFooterView(); mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop); mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front); @@ -957,8 +943,8 @@ public class StatusBar extends SystemUI implements DemoMode, scrimBehind, scrimInFront, mLockscreenWallpaper, (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color), scrimsVisible -> { - if (mStatusBarWindowManager != null) { - mStatusBarWindowManager.setScrimsVisibility(scrimsVisible); + if (mStatusBarWindowController != null) { + mStatusBarWindowController.setScrimsVisibility(scrimsVisible); } }, DozeParameters.getInstance(mContext), mContext.getSystemService(AlarmManager.class)); @@ -966,12 +952,13 @@ public class StatusBar extends SystemUI implements DemoMode, Runnable runnable = () -> { boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; mScrimController.setDrawBehindAsSrc(asSrc); - mStackScroller.setDrawBackgroundAsSrc(asSrc); + mNotificationPanel.setDrawBackgroundAsSrc(asSrc); }; mBackdrop.setOnVisibilityChangedRunnable(runnable); runnable.run(); } - mStackScroller.setScrimController(mScrimController); + mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf, + mHeadsUpManager, mNotificationIconAreaController, mScrimController); mDozeScrimController = new DozeScrimController(mScrimController, context, DozeParameters.getInstance(context)); @@ -1113,11 +1100,10 @@ public class StatusBar extends SystemUI implements DemoMode, (NotificationShelf) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_shelf, mStackScroller, false); mNotificationShelf.setOnActivatedListener(this); - mStackScroller.setShelf(mNotificationShelf); mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); - mNotificationShelf.setStatusBarState(mState); } + @Override public void onDensityOrFontScaleChanged() { MessagingMessage.dropCache(); MessagingGroup.dropCache(); @@ -1142,17 +1128,10 @@ public class StatusBar extends SystemUI implements DemoMode, } mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); mHeadsUpManager.onDensityOrFontScaleChanged(); - - inflateFooterView(); - inflateEmptyShadeView(); - reevaluateStyles(); } - private void onThemeChanged() { - reevaluateStyles(); - - // Clock and bottom icons - mNotificationPanel.onThemeChanged(); + @Override + public void onThemeChanged() { // The status bar on the keyguard is a special layout. if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged(); // Recreate Indication controller because internal references changed @@ -1173,11 +1152,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - private void reevaluateStyles() { - updateFooter(); - updateEmptyShadeView(); - } - @Override public void onOverlayChanged() { if (mBrightnessMirrorController != null) { @@ -1195,37 +1169,6 @@ public class StatusBar extends SystemUI implements DemoMode, if (mBrightnessMirrorController != null) { mBrightnessMirrorController.onUiModeChanged(); } - if (mStackScroller != null) { - mStackScroller.onUiModeChanged(); - } - } - - private void inflateEmptyShadeView() { - if (mStackScroller == null) { - return; - } - mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( - R.layout.status_bar_no_notifications, mStackScroller, false); - mEmptyShadeView.setText(R.string.empty_shade_text); - mStackScroller.setEmptyShadeView(mEmptyShadeView); - } - - @VisibleForTesting - protected void inflateFooterView() { - if (mStackScroller == null) { - return; - } - - mFooterView = (FooterView) LayoutInflater.from(mContext).inflate( - R.layout.status_bar_notification_footer, mStackScroller, false); - mFooterView.setDismissButtonClickListener(v -> { - mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); - clearAllNotifications(); - }); - mFooterView.setManageButtonClickListener(v -> { - manageNotifications(); - }); - mStackScroller.setFooterView(mFooterView); } protected void createUserSwitcher() { @@ -1239,105 +1182,6 @@ public class StatusBar extends SystemUI implements DemoMode, R.layout.super_status_bar, null); } - public void manageNotifications() { - Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS); - startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); - } - - public void clearAllNotifications() { - // animate-swipe all dismissable notifications, then animate the shade closed - int numChildren = mStackScroller.getChildCount(); - - final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); - final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); - for (int i = 0; i < numChildren; i++) { - final View child = mStackScroller.getChildAt(i); - if (child instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - boolean parentVisible = false; - boolean hasClipBounds = child.getClipBounds(mTmpRect); - if (mStackScroller.canChildBeDismissed(child)) { - viewsToRemove.add(row); - if (child.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - viewsToHide.add(child); - parentVisible = true; - } - } else if (child.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - parentVisible = true; - } - List<ExpandableNotificationRow> children = row.getNotificationChildren(); - if (children != null) { - for (ExpandableNotificationRow childRow : children) { - viewsToRemove.add(childRow); - if (parentVisible && row.areChildrenExpanded() - && mStackScroller.canChildBeDismissed(childRow)) { - hasClipBounds = childRow.getClipBounds(mTmpRect); - if (childRow.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - viewsToHide.add(childRow); - } - } - } - } - } - } - if (viewsToRemove.isEmpty()) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - return; - } - - addPostCollapseAction(() -> { - mStackScroller.setDismissAllInProgress(false); - for (ExpandableNotificationRow rowToRemove : viewsToRemove) { - if (mStackScroller.canChildBeDismissed(rowToRemove)) { - mEntryManager.removeNotification(rowToRemove.getEntry().key, null); - } else { - rowToRemove.resetTranslation(); - } - } - try { - mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId()); - } catch (Exception ex) { - } - }); - - performDismissAllAnimations(viewsToHide); - - } - - private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { - Runnable animationFinishAction = () -> { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); - }; - - if (hideAnimatedList.isEmpty()) { - animationFinishAction.run(); - return; - } - - // let's disable our normal animations - mStackScroller.setDismissAllInProgress(true); - - // Decrease the delay for every row we animate to give the sense of - // accelerating the swipes - int rowDelayDecrement = 10; - int currentDelay = 140; - int totalDelay = 180; - int numItems = hideAnimatedList.size(); - for (int i = numItems - 1; i >= 0; i--) { - View view = hideAnimatedList.get(i); - Runnable endRunnable = null; - if (i == 0) { - endRunnable = animationFinishAction; - } - mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260); - currentDelay = Math.max(50, currentDelay - rowDelayDecrement); - totalDelay += currentDelay; - } - } - protected void startKeyguard() { Trace.beginSection("StatusBar#startKeyguard"); KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); @@ -1410,7 +1254,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onPerformRemoveNotification(StatusBarNotification n) { - if (mStackScroller.hasPulsingNotifications() && + if (mNotificationPanel.hasPulsingNotifications() && !mHeadsUpManager.hasNotifications()) { // We were showing a pulse for a notification, but no notifications are pulsing anymore. // Finish the pulse. @@ -1422,7 +1266,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void updateNotificationViews() { // The function updateRowStates depends on both of these being non-null, so check them here. // We may be called before they are set from DeviceProvisionedController's callback. - if (mStackScroller == null || mScrimController == null) return; + if (mScrimController == null) return; // Do not modify the notifications during collapse. if (isCollapsing()) { @@ -1432,9 +1276,7 @@ public class StatusBar extends SystemUI implements DemoMode, mViewHierarchyManager.updateNotificationViews(); - updateSpeedBumpIndex(); - updateFooter(); - updateEmptyShadeView(); + mNotificationPanel.updateNotificationViews(); updateQsExpansionEnabled(); @@ -1501,61 +1343,6 @@ public class StatusBar extends SystemUI implements DemoMode, mQSPanel.clickTile(tile); } - @VisibleForTesting - protected void updateFooter() { - boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(); - boolean showFooterView = (showDismissView || - mEntryManager.getNotificationData().getActiveNotifications().size() != 0) - && mState != StatusBarState.KEYGUARD - && !mRemoteInputManager.getController().isRemoteInputActive(); - - mStackScroller.updateFooterView(showFooterView, showDismissView); - } - - /** - * Return whether there are any clearable notifications - */ - private boolean hasActiveClearableNotifications() { - int childCount = mStackScroller.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mStackScroller.getChildAt(i); - if (!(child instanceof ExpandableNotificationRow)) { - continue; - } - if (((ExpandableNotificationRow) child).canViewBeDismissed()) { - return true; - } - } - return false; - } - - private void updateEmptyShadeView() { - boolean showEmptyShadeView = - mState != StatusBarState.KEYGUARD && - mEntryManager.getNotificationData().getActiveNotifications().size() == 0; - mNotificationPanel.showEmptyShadeView(showEmptyShadeView); - } - - private void updateSpeedBumpIndex() { - int speedBumpIndex = 0; - int currentIndex = 0; - final int N = mStackScroller.getChildCount(); - for (int i = 0; i < N; i++) { - View view = mStackScroller.getChildAt(i); - if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) { - continue; - } - ExpandableNotificationRow row = (ExpandableNotificationRow) view; - currentIndex++; - if (!mEntryManager.getNotificationData().isAmbient( - row.getStatusBarNotification().getKey())) { - speedBumpIndex = currentIndex; - } - } - boolean noAmbient = speedBumpIndex == N; - mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient); - } - public static boolean isTopLevelChild(Entry entry) { return entry.row.getParent() instanceof NotificationStackScrollLayout; } @@ -1572,7 +1359,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (SPEW) { final boolean clearable = hasActiveNotifications() && - hasActiveClearableNotifications(); + mNotificationPanel.hasActiveClearableNotifications(); Log.d(TAG, "setAreThereNotifications: N=" + mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" + hasActiveNotifications() + " clearable=" + clearable); @@ -1702,7 +1489,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBackdrop.animate().cancel(); mBackdrop.setAlpha(1f); } - mStatusBarWindowManager.setBackdropShowing(true); + mStatusBarWindowController.setBackdropShowing(true); metaDataChanged = true; if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork"); @@ -1762,9 +1549,9 @@ public class StatusBar extends SystemUI implements DemoMode, // We are unlocking directly - no animation! mBackdrop.setVisibility(View.GONE); mBackdropBack.setImageDrawable(null); - mStatusBarWindowManager.setBackdropShowing(false); + mStatusBarWindowController.setBackdropShowing(false); } else { - mStatusBarWindowManager.setBackdropShowing(false); + mStatusBarWindowController.setBackdropShowing(false); mBackdrop.animate() .alpha(SRC_MIN_ALPHA) .setInterpolator(Interpolators.ACCELERATE_DECELERATE) @@ -1776,12 +1563,12 @@ public class StatusBar extends SystemUI implements DemoMode, mBackdropBack.setImageDrawable(null); mHandler.post(mHideBackdropFront); }); - if (mKeyguardFadingAway) { + if (mKeyguardMonitor.isKeyguardFadingAway()) { mBackdrop.animate() // Make it disappear faster, as the focus should be on the activity // behind. - .setDuration(mKeyguardFadingAwayDuration / 2) - .setStartDelay(mKeyguardFadingAwayDelay) + .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2) + .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay()) .setInterpolator(Interpolators.LINEAR) .start(); } @@ -1886,7 +1673,7 @@ public class StatusBar extends SystemUI implements DemoMode, /** * Reapplies the disable flags as last requested by StatusBarManager. * - * This needs to be called if state used by {@link #adjustDisableFlags} changes. + * This needs to be called if state used by adjustDisableFlags changes. */ public void recomputeDisableFlags(boolean animate) { mCommandQueue.recomputeDisableFlags(animate); @@ -1896,7 +1683,7 @@ public class StatusBar extends SystemUI implements DemoMode, return new StatusBar.H(); } - private void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, + public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags) { startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags); } @@ -1918,27 +1705,23 @@ public class StatusBar extends SystemUI implements DemoMode, } public void setQsExpanded(boolean expanded) { - mStatusBarWindowManager.setQsExpanded(expanded); + mStatusBarWindowController.setQsExpanded(expanded); mNotificationPanel.setStatusAccessibilityImportance(expanded ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } - public boolean isGoingToNotificationShade() { - return mLeaveOpenOnKeyguardHide; - } - public boolean isWakeUpComingFromTouch() { return mWakeUpComingFromTouch; } public boolean isFalsingThresholdNeeded() { - return getBarState() == StatusBarState.KEYGUARD; + return mStatusBarStateController.getState() == StatusBarState.KEYGUARD; } @Override public boolean isDozing() { - return mDozing && mStackScroller.isFullyDark(); + return mDozing && mNotificationPanel.isFullyDark(); } @Override @@ -2001,31 +1784,31 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { if (inPinnedMode) { - mStatusBarWindowManager.setHeadsUpShowing(true); - mStatusBarWindowManager.setForceStatusBarVisible(true); + mStatusBarWindowController.setHeadsUpShowing(true); + mStatusBarWindowController.setForceStatusBarVisible(true); if (mNotificationPanel.isFullyCollapsed()) { // We need to ensure that the touchable region is updated before the window will be // resized, in order to not catch any touches. A layout will ensure that // onComputeInternalInsets will be called and after that we can resize the layout. Let's // make sure that the window stays small for one frame until the touchableRegion is set. mNotificationPanel.requestLayout(); - mStatusBarWindowManager.setForceWindowCollapsed(true); + mStatusBarWindowController.setForceWindowCollapsed(true); mNotificationPanel.post(() -> { - mStatusBarWindowManager.setForceWindowCollapsed(false); + mStatusBarWindowController.setForceWindowCollapsed(false); }); } } else { if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) { // We are currently tracking or is open and the shade doesn't need to be kept // open artificially. - mStatusBarWindowManager.setHeadsUpShowing(false); + mStatusBarWindowController.setHeadsUpShowing(false); } else { // we need to keep the panel open artificially, let's wait until the animation // is finished. mHeadsUpManager.setHeadsUpGoingAway(true); - mStackScroller.runAfterAnimationFinished(() -> { + mNotificationPanel.runAfterAnimationFinished(() -> { if (!mHeadsUpManager.hasPinnedHeadsUp()) { - mStatusBarWindowManager.setHeadsUpShowing(false); + mStatusBarWindowController.setHeadsUpShowing(false); mHeadsUpManager.setHeadsUpGoingAway(false); } mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed(); @@ -2065,9 +1848,9 @@ public class StatusBar extends SystemUI implements DemoMode, public void setPanelExpanded(boolean isExpanded) { mPanelExpanded = isExpanded; updateHideIconsForBouncer(false /* animate */); - mStatusBarWindowManager.setPanelExpanded(isExpanded); + mStatusBarWindowController.setPanelExpanded(isExpanded); mVisualStabilityManager.setPanelExpanded(isExpanded); - if (isExpanded && getBarState() != StatusBarState.KEYGUARD) { + if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) { if (DEBUG) { Log.v(TAG, "clearing notification effects from setExpandedHeight"); } @@ -2079,7 +1862,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - public NotificationStackScrollLayout getNotificationScrollLayout() { + public ViewGroup getNotificationScrollLayout() { return mStackScroller; } @@ -2274,7 +2057,7 @@ public class StatusBar extends SystemUI implements DemoMode, // Expand the window to encompass the full screen in anticipation of the drag. // This is only possible to do atomically because the status bar is at the top of the screen! - mStatusBarWindowManager.setPanelVisible(true); + mStatusBarWindowController.setPanelVisible(true); visibilityChanged(true); recomputeDisableFlags(!force /* animate */); @@ -2348,7 +2131,7 @@ public class StatusBar extends SystemUI implements DemoMode, + mNotificationPanel.canPanelBeCollapsed()); if (mStatusBarWindow != null && mNotificationPanel.canPanelBeCollapsed()) { // release focus immediately to kick off focus change transition - mStatusBarWindowManager.setStatusBarFocusable(false); + mStatusBarWindowController.setStatusBarFocusable(false); mStatusBarWindow.cancelExpandHelper(); mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); @@ -2420,8 +2203,8 @@ public class StatusBar extends SystemUI implements DemoMode, visibilityChanged(false); // Shrink the window to the size of the status bar only - mStatusBarWindowManager.setPanelVisible(false); - mStatusBarWindowManager.setForceStatusBarVisible(false); + mStatusBarWindowController.setPanelVisible(false); + mStatusBarWindowController.setForceStatusBarVisible(false); // Close any guts that might be visible mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, @@ -2802,9 +2585,9 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.dump(fd, pw, args); } pw.println(" mStackScroller: "); - if (mStackScroller != null) { + if (mStackScroller instanceof Dumpable) { pw.print (" "); - mStackScroller.dump(fd, pw, args); + ((Dumpable) mStackScroller).dump(fd, pw, args); } pw.println(" Theme:"); String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + ""; @@ -2894,25 +2677,11 @@ public class StatusBar extends SystemUI implements DemoMode, private void addStatusBarWindow() { makeStatusBarView(); - mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); + mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this, - new RemoteInputController.Delegate() { - public void setRemoteInputActive(NotificationData.Entry entry, - boolean remoteInputActive) { - mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); - entry.row.notifyHeightChanged(true /* needsAnimation */); - updateFooter(); - } - public void lockScrollTo(NotificationData.Entry entry) { - mStackScroller.lockScrollTo(entry.row); - } - public void requestDisallowLongPressAndDismiss() { - mStackScroller.requestDisallowLongPress(); - mStackScroller.requestDisallowDismiss(); - } - }); - mRemoteInputManager.getController().addCallback(mStatusBarWindowManager); - mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); + mNotificationPanel.createRemoteInputDelegate()); + mRemoteInputManager.getController().addCallback(mStatusBarWindowController); + mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); } // called by makeStatusbar and also by PhoneStatusBarView @@ -3111,7 +2880,7 @@ public class StatusBar extends SystemUI implements DemoMode, private void executeWhenUnlocked(OnDismissAction action) { if (mStatusBarKeyguardViewManager.isShowing()) { - mLeaveOpenOnKeyguardHide = true; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); } dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */); } @@ -3124,7 +2893,7 @@ public class StatusBar extends SystemUI implements DemoMode, boolean afterKeyguardGone) { if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP && mUnlockMethodCache.canSkipBouncer() - && !mLeaveOpenOnKeyguardHide + && !mStatusBarStateController.leaveOpenOnKeyguardHide() && isPulsing()) { // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a pulse. // TODO: Factor this transition out of BiometricUnlockController. @@ -3222,8 +2991,8 @@ public class StatusBar extends SystemUI implements DemoMode, int oldBarHeight = mNaturalBarHeight; mNaturalBarHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); - if (mStatusBarWindowManager != null && mNaturalBarHeight != oldBarHeight) { - mStatusBarWindowManager.setBarHeight(mNaturalBarHeight); + if (mStatusBarWindowController != null && mNaturalBarHeight != oldBarHeight) { + mStatusBarWindowController.setBarHeight(mNaturalBarHeight); } mMaxAllowedKeyguardNotifications = res.getInteger( R.integer.keyguard_max_notification_count); @@ -3372,7 +3141,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void postQSRunnableDismissingKeyguard(final Runnable runnable) { mHandler.post(() -> { - mLeaveOpenOnKeyguardHide = true; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); executeRunnableDismissingKeyguard(() -> mHandler.post(runnable), null, false, false, false); }); @@ -3415,6 +3184,8 @@ public class StatusBar extends SystemUI implements DemoMode, mContext.unregisterReceiver(mBroadcastReceiver); mContext.unregisterReceiver(mDemoReceiver); mAssistManager.destroy(); + mHeadsUpManager.destroy(); + mStatusBarStateController.removeListener(this); if (mQSPanel != null && mQSPanel.getHost() != null) { mQSPanel.getHost().destroy(); @@ -3501,13 +3272,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - /** - * @return The {@link StatusBarState} the status bar is in. - */ - public int getBarState() { - return mState; - } - @Override public boolean isPresenterFullyCollapsed() { return mNotificationPanel.isFullyCollapsed(); @@ -3515,7 +3279,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void showKeyguard() { mKeyguardRequested = true; - mLeaveOpenOnKeyguardHide = false; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(false); mPendingRemoteInputView = null; updateIsKeyguard(); mAssistManager.onLockscreenShown(); @@ -3568,11 +3332,10 @@ public class StatusBar extends SystemUI implements DemoMode, } mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) { - setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER); + mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER); } else { - setBarState(StatusBarState.KEYGUARD); + mStatusBarStateController.setState(StatusBarState.KEYGUARD); } - updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); updatePanelExpansionForKeyguard(); if (mDraggedDownRow != null) { mDraggedDownRow.setUserLocked(false); @@ -3631,7 +3394,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateScrimController(); updateMediaMetaData(false, true); mNotificationPanel.setAlpha(1); - mStackScroller.setParentNotFullyVisible(true); + mNotificationPanel.setParentNotFullyVisible(true); mNotificationPanel.animate() .alpha(0) .setStartDelay(FADE_KEYGUARD_START_DELAY) @@ -3707,14 +3470,14 @@ public class StatusBar extends SystemUI implements DemoMode, public boolean hideKeyguardImpl() { mIsKeyguard = false; Trace.beginSection("StatusBar#hideKeyguard"); - boolean staying = mLeaveOpenOnKeyguardHide; - setBarState(StatusBarState.SHADE); + boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide(); + mStatusBarStateController.setState(StatusBarState.SHADE); View viewToClick = null; - if (mLeaveOpenOnKeyguardHide) { + if (mStatusBarStateController.leaveOpenOnKeyguardHide()) { if (!mKeyguardRequested) { - mLeaveOpenOnKeyguardHide = false; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(false); } - long delay = calculateGoingToFullShadeDelay(); + long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay(); mNotificationPanel.animateToFullShade(delay); if (mDraggedDownRow != null) { mDraggedDownRow.setUserLocked(false); @@ -3733,7 +3496,6 @@ public class StatusBar extends SystemUI implements DemoMode, } else if (!mNotificationPanel.isCollapsing()) { instantCollapseNotificationPanel(); } - updateKeyguardState(staying, false /* fromShadeLocked */); if (viewToClick != null && viewToClick.isAttachedToWindow()) { viewToClick.callOnClick(); @@ -3759,15 +3521,10 @@ public class StatusBar extends SystemUI implements DemoMode, } } - public long calculateGoingToFullShadeDelay() { - return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; - } - /** * Notifies the status bar that Keyguard is going away very soon. */ public void keyguardGoingAway() { - // Treat Keyguard exit animation as an app transition to achieve nice transition for status // bar. mKeyguardMonitor.notifyKeyguardGoingAway(true); @@ -3782,9 +3539,6 @@ public class StatusBar extends SystemUI implements DemoMode, * @param fadeoutDuration the duration of the exit animation, in milliseconds */ public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) { - mKeyguardFadingAway = true; - mKeyguardFadingAwayDelay = delay; - mKeyguardFadingAwayDuration = fadeoutDuration; mCommandQueue.appTransitionStarting(startTime + fadeoutDuration - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); @@ -3795,15 +3549,10 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration); } - public boolean isKeyguardFadingAway() { - return mKeyguardFadingAway; - } - /** * Notifies that the Keyguard fading away animation is done. */ public void finishKeyguardFadingAway() { - mKeyguardFadingAway = false; mKeyguardMonitor.notifyKeyguardDoneFading(); mScrimController.setExpansionAffectsAlpha(true); } @@ -3836,52 +3585,10 @@ public class StatusBar extends SystemUI implements DemoMode, } } - protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) { - Trace.beginSection("StatusBar#updateKeyguardState"); - if (mState == StatusBarState.KEYGUARD) { - mKeyguardIndicationController.setVisible(true); - boolean dozingAnimated = mDozingRequested - && DozeParameters.getInstance(mContext).shouldControlScreenOff(); - mNotificationPanel.resetViews(dozingAnimated); - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); - } - if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables(); - if (mAmbientIndicationContainer != null) { - mAmbientIndicationContainer.setVisibility(View.VISIBLE); - } - } else { - mKeyguardIndicationController.setVisible(false); - if (mKeyguardUserSwitcher != null) { - mKeyguardUserSwitcher.setKeyguard(false, - goingToFullShade || - mState == StatusBarState.SHADE_LOCKED || - fromShadeLocked); - } - if (mAmbientIndicationContainer != null) { - mAmbientIndicationContainer.setVisibility(View.INVISIBLE); - } - } - mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); - updateTheme(); - updateDozingState(); - updatePublicMode(); - updateStackScrollerState(goingToFullShade, fromShadeLocked); - mEntryManager.updateNotifications(); - checkBarModes(); - updateScrimController(); - updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); - mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), - mUnlockMethodCache.isMethodSecure(), - mStatusBarKeyguardViewManager.isOccluded()); - Trace.endSection(); - } - /** * Switches theme from light to dark and vice-versa. */ protected void updateTheme() { - final boolean inflated = mStackScroller != null && mStatusBarWindowManager != null; // Lock wallpaper defines the color of the majority of the views, hence we'll use it // to set our default theme. @@ -3890,24 +3597,7 @@ public class StatusBar extends SystemUI implements DemoMode, final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; if (mContext.getThemeResId() != themeResId) { mContext.setTheme(themeResId); - if (inflated) { - onThemeChanged(); - } - } - - if (inflated) { - int which; - if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { - which = WallpaperManager.FLAG_LOCK; - } else { - which = WallpaperManager.FLAG_SYSTEM; - } - final boolean useDarkText = mColorExtractor.getColors(which, - true /* ignoreVisibility */).supportsDarkText(); - mStackScroller.updateDecorViews(useDarkText); - - // Make sure we have the correct navbar/statusbar colors. - mStatusBarWindowManager.setKeyguardDark(useDarkText); + Dependency.get(ConfigurationController.class).notifyThemeChanged(); } } @@ -3920,32 +3610,14 @@ public class StatusBar extends SystemUI implements DemoMode, boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup()) || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard); - mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); mDozeScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); - mNotificationPanel.setDozing(mDozing, animate); + mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation); mNotificationLogger.setDozing(mDozing); updateQsExpansionEnabled(); Trace.endSection(); } - public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) { - if (mStackScroller == null) return; - boolean onKeyguard = mState == StatusBarState.KEYGUARD; - boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode(); - if (mHeadsUpAppearanceController != null) { - mHeadsUpAppearanceController.setPublicMode(publicMode); - } - mStackScroller.setHideSensitive(publicMode, goingToFullShade); - mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */); - mStackScroller.setExpandingEnabled(!onKeyguard); - ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); - mStackScroller.setActivatedChild(null); - if (activatedChild != null) { - activatedChild.makeInactive(false /* animate */); - } - } - public void userActivity() { if (mState == StatusBarState.KEYGUARD) { mKeyguardViewMediatorCallback.userActivity(); @@ -4037,7 +3709,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onActivated(ActivatableNotificationView view) { onActivated((View) view); - mStackScroller.setActivatedChild(view); + mNotificationPanel.setActivatedChild(view); } public void onActivated(View view) { @@ -4045,45 +3717,78 @@ public class StatusBar extends SystemUI implements DemoMode, MetricsEvent.ACTION_LS_NOTE, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again); - ActivatableNotificationView previousView = mStackScroller.getActivatedChild(); + ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild(); if (previousView != null) { previousView.makeInactive(true /* animate */); } } - /** - * @param state The {@link StatusBarState} to set. - */ - public void setBarState(int state) { + @Override + public void onStatePreChange(int oldState, int newState) { + // If we're visible and switched to SHADE_LOCKED (the user dragged // down on the lockscreen), clear notification LED, vibration, // ringing. // Other transitions are covered in handleVisibleToUserChanged(). - if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED - || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) { + if (mVisible && (newState == StatusBarState.SHADE_LOCKED + || (Dependency.get(StatusBarStateController.class).goingToFullShade()))) { clearNotificationEffects(); } - if (state == StatusBarState.KEYGUARD) { + if (newState == StatusBarState.KEYGUARD) { mRemoteInputManager.removeRemoteInputEntriesKeptUntilCollapsed(); maybeEscalateHeadsUp(); } - mState = state; - mGroupManager.setStatusBarState(state); - mHeadsUpManager.setStatusBarState(state); - mFalsingManager.setStatusBarState(state); - mStatusBarWindowManager.setStatusBarState(state); - mStackScroller.setStatusBarState(state); + } + + @Override + public void onStateChanged(int newState) { + mState = newState; updateReportRejectedTouchVisibility(); updateDozing(); updateTheme(); touchAutoDim(); - mNotificationShelf.setStatusBarState(state); + Trace.beginSection("StatusBar#updateKeyguardState"); + if (mState == StatusBarState.KEYGUARD) { + mKeyguardIndicationController.setVisible(true); + boolean dozingAnimated = mDozingRequested + && DozeParameters.getInstance(mContext).shouldControlScreenOff(); + mNotificationPanel.resetViews(dozingAnimated); + if (mKeyguardUserSwitcher != null) { + mKeyguardUserSwitcher.setKeyguard(true, + mStatusBarStateController.fromShadeLocked()); + } + if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables(); + if (mAmbientIndicationContainer != null) { + mAmbientIndicationContainer.setVisibility(View.VISIBLE); + } + } else { + mKeyguardIndicationController.setVisible(false); + if (mKeyguardUserSwitcher != null) { + mKeyguardUserSwitcher.setKeyguard(false, + mStatusBarStateController.goingToFullShade() || + mState == StatusBarState.SHADE_LOCKED || + mStatusBarStateController.fromShadeLocked()); + } + if (mAmbientIndicationContainer != null) { + mAmbientIndicationContainer.setVisibility(View.INVISIBLE); + } + } + updateDozingState(); + updatePublicMode(); + mEntryManager.updateNotifications(); + checkBarModes(); + updateScrimController(); + updateMediaMetaData(false, mState != StatusBarState.KEYGUARD); + mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(), + mUnlockMethodCache.isMethodSecure(), + mStatusBarKeyguardViewManager.isOccluded()); + Trace.endSection(); } @Override public void onActivationReset(ActivatableNotificationView view) { - if (view == mStackScroller.getActivatedChild()) { - mStackScroller.setActivatedChild(null); + if (view == mNotificationPanel.getActivatedChild()) { + mNotificationPanel.setActivatedChild(null); onActivationReset((View)view); } } @@ -4101,7 +3806,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (!isPresenterFullyCollapsed()) { // if we set it not to be focusable when collapsing, we have to undo it when we aborted // the closing - mStatusBarWindowManager.setStatusBarFocusable(true); + mStatusBarWindowController.setStatusBarFocusable(true); } } @@ -4149,8 +3854,9 @@ public class StatusBar extends SystemUI implements DemoMode, return mMaxKeyguardNotifications; } - public int getMaxNotificationsWhileLocked() { - return getMaxNotificationsWhileLocked(false /* recompute */); + @Override + public void onUpdateRowStates() { + mNotificationPanel.onUpdateRowStates(); } // TODO: Figure out way to remove these. @@ -4170,60 +3876,6 @@ public class StatusBar extends SystemUI implements DemoMode, return mNotificationPanel.getKeyguardBottomAreaView(); } - // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ - - - /* Only ever called as a consequence of a lockscreen expansion gesture. */ - @Override - public boolean onDraggedDown(View startingChild, int dragLengthY) { - if (mState == StatusBarState.KEYGUARD - && hasActiveNotifications() && (!isDozing() || isPulsing())) { - mLockscreenGestureLogger.write( - MetricsEvent.ACTION_LS_SHADE, - (int) (dragLengthY / mDisplayMetrics.density), - 0 /* velocityDp - N/A */); - - // We have notifications, go to locked shade. - goToLockedShade(startingChild); - if (startingChild instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild; - row.onExpandedByGesture(true /* drag down is always an open */); - } - return true; - } else { - // abort gesture. - return false; - } - } - - @Override - public void onDragDownReset() { - mStackScroller.setDimmed(true /* dimmed */, true /* animated */); - mStackScroller.resetScrollPosition(); - mStackScroller.resetCheckSnoozeLeavebehind(); - } - - @Override - public void onCrossedThreshold(boolean above) { - mStackScroller.setDimmed(!above /* dimmed */, true /* animate */); - } - - @Override - public void onTouchSlopExceeded() { - mStackScroller.cancelLongPress(); - mStackScroller.checkSnoozeLeavebehind(); - } - - @Override - public void setEmptyDragAmount(float amount) { - mNotificationPanel.setEmptyDragAmount(amount); - } - - @Override - public boolean isFalsingCheckNeeded() { - return mState == StatusBarState.KEYGUARD; - } - /** * If secure with redaction: Show bouncer, go to unlocked shade. * @@ -4253,25 +3905,24 @@ public class StatusBar extends SystemUI implements DemoMode, || !mLockscreenUserManager.shouldShowLockscreenNotifications() || mFalsingManager.shouldEnforceBouncer(); if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) { - mLeaveOpenOnKeyguardHide = true; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); showBouncerIfKeyguard(); mDraggedDownRow = row; mPendingRemoteInputView = null; } else { mNotificationPanel.animateToFullShade(0 /* delay */); - setBarState(StatusBarState.SHADE_LOCKED); - updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */); + mStatusBarStateController.setState(StatusBarState.SHADE_LOCKED); } } public void onLockedNotificationImportanceChange(OnDismissAction dismissAction) { - mLeaveOpenOnKeyguardHide = true; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); dismissKeyguardThenExecute(dismissAction, true /* afterKeyguardGone */); } @Override public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) { - mLeaveOpenOnKeyguardHide = true; + mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); showBouncer(true /* scrimmed */); mPendingRemoteInputView = clicked; } @@ -4449,20 +4100,10 @@ public class StatusBar extends SystemUI implements DemoMode, */ public void goToKeyguard() { if (mState == StatusBarState.SHADE_LOCKED) { - mStackScroller.onGoToKeyguard(); - setBarState(StatusBarState.KEYGUARD); - updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/); + mStatusBarStateController.setState(StatusBarState.KEYGUARD); } } - public long getKeyguardFadingAwayDelay() { - return mKeyguardFadingAwayDelay; - } - - public long getKeyguardFadingAwayDuration() { - return mKeyguardFadingAwayDuration; - } - public void setBouncerShowing(boolean bouncerShowing) { mBouncerShowing = bouncerShowing; if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); @@ -4492,14 +4133,13 @@ public class StatusBar extends SystemUI implements DemoMode, mDeviceInteractive = false; mWakeUpComingFromTouch = false; mWakeUpTouchLocation = null; - mStackScroller.setAnimationsEnabled(false); mVisualStabilityManager.setScreenOn(false); updateVisibleToUser(); // We need to disable touch events because these might // collapse the panel after we expanded it, and thus we would end up with a blank // Keyguard. - mNotificationPanel.setTouchDisabled(true); + mNotificationPanel.setTouchAndAnimationDisabled(true); mStatusBarWindow.cancelCurrentTouch(); if (mLaunchCameraOnFinishedGoingToSleep) { mLaunchCameraOnFinishedGoingToSleep = false; @@ -4520,9 +4160,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onStartedWakingUp() { mDeviceInteractive = true; - mStackScroller.setAnimationsEnabled(true); mVisualStabilityManager.setScreenOn(true); - mNotificationPanel.setTouchDisabled(false); + mNotificationPanel.setTouchAndAnimationDisabled(false); mDozeServiceHost.stopDozing(); updateVisibleToUser(); updateIsKeyguard(); @@ -4718,7 +4357,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mDozing != dozing) { mDozing = dozing; mKeyguardViewMediator.setAodShowing(mDozing); - mStatusBarWindowManager.setDozing(mDozing); + mStatusBarWindowController.setDozing(mDozing); mStatusBarKeyguardViewManager.setDozing(mDozing); if (mAmbientIndicationContainer instanceof DozeReceiver) { ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing); @@ -4948,7 +4587,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void setDozeScreenBrightness(int value) { - mStatusBarWindowManager.setDozeScreenBrightness(value); + mStatusBarWindowController.setDozeScreenBrightness(value); } @Override @@ -4992,7 +4631,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected IStatusBarService mBarService; // all notifications - protected NotificationStackScrollLayout mStackScroller; + protected ViewGroup mStackScroller; protected NotificationGroupManager mGroupManager; @@ -5033,7 +4672,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected RecentsComponent mRecents; protected NotificationShelf mNotificationShelf; - protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; protected AssistManager mAssistManager; @@ -5229,7 +4867,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (Looper.getMainLooper().isCurrentThread()) { collapsePanel(); } else { - mStackScroller.post(this::collapsePanel); + Dependency.get(Dependency.MAIN_HANDLER).post(this::collapsePanel); } } @@ -5508,33 +5146,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - /** - * Updates expanded, dimmed and locked states of notification rows. - */ - @Override - public void onUpdateRowStates() { - // The following views will be moved to the end of mStackScroller. This counter represents - // the offset from the last child. Initialized to 1 for the very last position. It is post- - // incremented in the following "changeViewPosition" calls so that its value is correct for - // subsequent calls. - int offsetFromEnd = 1; - if (mFooterView != null) { - mStackScroller.changeViewPosition(mFooterView, - mStackScroller.getChildCount() - offsetFromEnd++); - } - - mStackScroller.changeViewPosition(mEmptyShadeView, - mStackScroller.getChildCount() - offsetFromEnd++); - - // No post-increment for this call because it is the last one. Make sure to add one if - // another "changeViewPosition" call is ever added. - mStackScroller.changeViewPosition(mNotificationShelf, - mStackScroller.getChildCount() - offsetFromEnd); - - // Scrim opacity varies based on notification count - mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount()); - } - protected void notifyHeadsUpGoingToSleep() { maybeEscalateHeadsUp(); } @@ -5581,11 +5192,6 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override - public void onZenChanged(int zen) { - updateEmptyShadeView(); - } - - @Override public void showAssistDisclosure() { if (mAssistManager != null) { mAssistManager.showDisclosure(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index c4424d8e3c97..e8389af85f22 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -44,7 +44,9 @@ import com.android.systemui.SystemUIFactory; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import java.io.PrintWriter; import java.util.ArrayList; @@ -74,7 +76,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private static String TAG = "StatusBarKeyguardViewManager"; protected final Context mContext; - private final StatusBarWindowManager mStatusBarWindowManager; + private final StatusBarWindowController mStatusBarWindowController; private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { @Override public void onFullyShown() { @@ -116,6 +118,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // Dismiss action to be launched when we stop dozing or the keyguard is gone. private DismissWithActionRequest mPendingWakeupAction; + private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @@ -135,7 +138,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mContext = context; mViewMediatorCallback = callback; mLockPatternUtils = lockPatternUtils; - mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); + mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback); } @@ -190,7 +193,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb */ public void show(Bundle options) { mShowing = true; - mStatusBarWindowManager.setKeyguardShowing(true); + mStatusBarWindowController.setKeyguardShowing(true); reset(true /* hideBouncerWhenShowing */); StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); @@ -342,11 +345,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public void setNeedsInput(boolean needsInput) { - mStatusBarWindowManager.setKeyguardNeedsInput(needsInput); + mStatusBarWindowController.setKeyguardNeedsInput(needsInput); } public boolean isUnlockWithWallpaper() { - return mStatusBarWindowManager.isShowingWallpaper(); + return mStatusBarWindowController.isShowingWallpaper(); } public void setOccluded(boolean occluded, boolean animate) { @@ -360,7 +363,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb new Runnable() { @Override public void run() { - mStatusBarWindowManager.setKeyguardOccluded(mOccluded); + mStatusBarWindowController.setKeyguardOccluded(mOccluded); reset(true /* hideBouncerWhenShowing */); } }); @@ -375,7 +378,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (mShowing) { mStatusBar.updateMediaMetaData(false, animate && !occluded); } - mStatusBarWindowManager.setKeyguardOccluded(occluded); + mStatusBarWindowController.setKeyguardOccluded(occluded); // setDozing(false) will call reset once we stop dozing. if (!mDozing) { @@ -425,8 +428,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { @Override public void run() { - mStatusBarWindowManager.setKeyguardShowing(false); - mStatusBarWindowManager.setKeyguardFadingAway(true); + mStatusBarWindowController.setKeyguardShowing(false); + mStatusBarWindowController.setKeyguardFadingAway(true); hideBouncer(true /* destroyView */); updateStates(); } @@ -434,7 +437,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void run() { mStatusBar.hideKeyguard(); - mStatusBarWindowManager.setKeyguardFadingAway(false); + mStatusBarWindowController.setKeyguardFadingAway(false); mViewMediatorCallback.keyguardGone(); executeAfterKeyguardGoneAction(); } @@ -456,7 +459,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { boolean staying = mStatusBar.hideKeyguard(); if (!staying) { - mStatusBarWindowManager.setKeyguardFadingAway(true); + mStatusBarWindowController.setKeyguardFadingAway(true); wakeAndUnlockDejank(); } else { mStatusBar.finishKeyguardFadingAway(); @@ -464,7 +467,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } updateStates(); - mStatusBarWindowManager.setKeyguardShowing(false); + mStatusBarWindowController.setKeyguardShowing(false); mViewMediatorCallback.keyguardGone(); } StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, @@ -481,7 +484,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public void onKeyguardFadedAway() { - mContainer.postDelayed(() -> mStatusBarWindowManager.setKeyguardFadingAway(false), + mContainer.postDelayed(() -> mStatusBarWindowController.setKeyguardFadingAway(false), 100); mStatusBar.finishKeyguardFadingAway(); mBiometricUnlockController.finishKeyguardFadingAway(); @@ -557,8 +560,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } private long getNavBarShowDelay() { - if (mStatusBar.isKeyguardFadingAway()) { - return mStatusBar.getKeyguardFadingAwayDelay(); + if (mKeyguardMonitor.isKeyguardFadingAway()) { + return mKeyguardMonitor.getKeyguardFadingAwayDelay(); } else if (mBouncer.isShowing()) { return NAV_BAR_SHOW_DELAY_BOUNCER; } else { @@ -599,7 +602,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { - mStatusBarWindowManager.setBouncerShowing(bouncerShowing); + mStatusBarWindowController.setBouncerShowing(bouncerShowing); mStatusBar.setBouncerShowing(bouncerShowing); } @@ -677,7 +680,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } public boolean isGoingToNotificationShade() { - return mStatusBar.isGoingToNotificationShade(); + return Dependency.get(StatusBarStateController.class).leaveOpenOnKeyguardHide(); } public boolean isSecure(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index a5716f2c2c09..46264f9dde1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -22,6 +22,7 @@ import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENAB import android.app.ActivityManager; import android.app.IActivityManager; +import android.app.WallpaperManager; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; @@ -36,11 +37,18 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.R; +import com.android.systemui.Dependency; import com.android.systemui.Dumpable; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.RemoteInputController.Callback; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -49,9 +57,9 @@ import java.lang.reflect.Field; /** * Encapsulates all logic for the status bar window state management. */ -public class StatusBarWindowManager implements RemoteInputController.Callback, Dumpable { +public class StatusBarWindowController implements Callback, Dumpable, ConfigurationListener { - private static final String TAG = "StatusBarWindowManager"; + private static final String TAG = "StatusBarWindowController"; private final Context mContext; private final WindowManager mWindowManager; @@ -68,13 +76,25 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D private final State mCurrentState = new State(); private OtherwisedCollapsedListener mListener; - public StatusBarWindowManager(Context context) { + private final StateListener mStateListener = this::setStatusBarState; + private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class); + + public StatusBarWindowController(Context context) { + this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(), + DozeParameters.getInstance(context)); + } + + @VisibleForTesting + StatusBarWindowController(Context context, WindowManager windowManager, + IActivityManager activityManager, DozeParameters dozeParameters) { mContext = context; - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - mActivityManager = ActivityManager.getService(); + mWindowManager = windowManager; + mActivityManager = activityManager; mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); - mDozeParameters = DozeParameters.getInstance(mContext); + mDozeParameters = dozeParameters; mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze(); + Dependency.get(StatusBarStateController.class).addListener(mStateListener); + Dependency.get(ConfigurationController.class).addCallback(this); } private boolean shouldEnableKeyguardScreenRotation() { @@ -121,7 +141,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D mScreenBrightnessDoze = value / 255f; } - public void setKeyguardDark(boolean dark) { + private void setKeyguardDark(boolean dark) { int vis = mStatusBarView.getSystemUiVisibility(); if (dark) { vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; @@ -149,6 +169,12 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D } else { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } + + if (state.dozing) { + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + } else { + mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + } } private void adjustScreenOrientation(State state) { @@ -371,9 +397,9 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D } /** - * @param state The {@link StatusBarState} of the status bar. + * @param state The {@link StatusBarStateController} of the status bar. */ - public void setStatusBarState(int state) { + private void setStatusBarState(int state) { mCurrentState.statusBarState = state; apply(mCurrentState); } @@ -433,7 +459,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("StatusBarWindowManager state:"); + pw.println("StatusBarWindowController state:"); pw.println(mCurrentState); } @@ -441,6 +467,23 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D return !mCurrentState.backdropShowing; } + @Override + public void onThemeChanged() { + StatusBarStateController state = Dependency.get(StatusBarStateController.class); + int which; + if (state.getState() == StatusBarState.KEYGUARD + || state.getState() == StatusBarState.SHADE_LOCKED) { + which = WallpaperManager.FLAG_LOCK; + } else { + which = WallpaperManager.FLAG_SYSTEM; + } + final boolean useDarkText = mColorExtractor.getColors(which, + true /* ignoreVisibility */).supportsDarkText(); + + // Make sure we have the correct navbar/statusbar colors. + setKeyguardDark(useDarkText); + } + private static class State { boolean keyguardShowing; boolean keyguardOccluded; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 5cc020290757..98f1a3693e06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -57,10 +57,12 @@ import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.view.FloatingActionMode; import com.android.internal.widget.FloatingToolbar; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.io.FileDescriptor; @@ -95,6 +97,8 @@ public class StatusBarWindowView extends FrameLayout { private boolean mTouchActive; private boolean mExpandAnimationRunning; private boolean mExpandAnimationPending; + private final StatusBarStateController + mStatusBarStateController = Dependency.get(StatusBarStateController.class); /** * If set to true, the current gesture started below the notch and we need to dispatch touch @@ -211,7 +215,8 @@ public class StatusBarWindowView extends FrameLayout { public void setService(StatusBar service) { mService = service; - setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService)); + setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, + mStackScrollLayout)); } @VisibleForTesting @@ -346,7 +351,7 @@ public class StatusBarWindowView extends FrameLayout { boolean intercept = false; if (mNotificationPanel.isFullyExpanded() && mStackScrollLayout.getVisibility() == View.VISIBLE - && mService.getBarState() == StatusBarState.KEYGUARD + && mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !mService.isBouncerShowing() && !mService.isDozing()) { intercept = mDragDownHelper.onInterceptTouchEvent(ev); @@ -371,7 +376,7 @@ public class StatusBarWindowView extends FrameLayout { mDoubleTapHelper.onTouchEvent(ev); handled = true; } - if ((mService.getBarState() == StatusBarState.KEYGUARD && !handled) + if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled) || mDragDownHelper.isDraggingDown()) { // we still want to finish our drag down gesture when locking the screen handled = mDragDownHelper.onTouchEvent(ev); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java index 8c631d9107df..0e5c8c105df8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java @@ -24,11 +24,14 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati */ public interface ConfigurationController extends CallbackController<ConfigurationListener> { + public void notifyThemeChanged(); + interface ConfigurationListener { default void onConfigChanged(Configuration newConfig) {} default void onDensityOrFontScaleChanged() {} default void onOverlayChanged() {} default void onUiModeChanged() {} + default void onThemeChanged() {} default void onLocaleListChanged() {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index ccfbb26a61d2..7b42dd4c9817 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -26,6 +26,7 @@ public interface KeyguardMonitor extends CallbackController<Callback> { boolean isKeyguardGoingAway(); long getKeyguardFadingAwayDuration(); long getKeyguardFadingAwayDelay(); + long calculateGoingToFullShadeDelay(); interface Callback { void onKeyguardShowingChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java index 5ead02f1f3f2..10cb09b75c16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java @@ -157,6 +157,11 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback return mKeyguardFadingAwayDuration; } + @Override + public long calculateGoingToFullShadeDelay() { + return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; + } + public void notifyKeyguardGoingAway(boolean keyguardGoingAway) { mKeyguardGoingAway = keyguardGoingAway; } diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 9ee55324efa2..6057614f26ee 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -21,28 +21,12 @@ LOCAL_MODULE_TAGS := tests LOCAL_JACK_FLAGS := --multi-dex native LOCAL_DX_FLAGS := --multi-dex -LOCAL_PROTOC_OPTIMIZE_TYPE := nano -LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/.. -LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors - LOCAL_PACKAGE_NAME := SystemUITests LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) \ - $(call all-Iaidl-files-under, src) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - LOCAL_STATIC_ANDROID_LIBRARIES := \ - SystemUI-core - -LOCAL_STATIC_JAVA_LIBRARIES := \ - metrics-helper-lib \ - android-support-test \ - mockito-target-inline-minus-junit4 \ - testables \ - truth-prebuilt \ + SystemUI-tests LOCAL_MULTILIB := both diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 64f96da09b08..8b1324a77a5e 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -72,6 +72,7 @@ tools:replace="android:authorities" android:authorities="${applicationId}.lifecycle-tests" android:exported="false" + android:enabled="false" android:multiprocess="true" /> <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider" android:authorities="com.android.systemui.test.keyguard.disabled" @@ -83,6 +84,7 @@ android:name="androidx.core.content.FileProvider" android:authorities="com.android.systemui.test.fileprovider" android:exported="false" + android:enabled="false" tools:replace="android:authorities" android:grantUriPermissions="true" /> </application> diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 644c0b347bde..cc969177ab2e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -21,6 +21,7 @@ import static com.android.systemui.tuner.TunablePadding.FLAG_START; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -226,4 +227,17 @@ public class ScreenDecorationsTest extends SysuiTestCase { verify(padding).destroy(); } + @Test + public void testUpdateRoundedCorners() { + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); + mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20); + + mScreenDecorations.start(); + assertEquals(mScreenDecorations.mRoundedDefault, 20); + + mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 5); + mScreenDecorations.onConfigurationChanged(null); + assertEquals(mScreenDecorations.mRoundedDefault, 5); + } } 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 91214732d4c5..8129b018a7be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java @@ -33,7 +33,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationInfo; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.StatusBarWindowManager; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; @@ -96,6 +96,6 @@ public class NonPhoneDependencyTest extends SysuiTestCase { viewHierarchyManager.setUpWithPresenter(mPresenter, entryManager, mListContainer); notificationListener.setUpWithPresenter(mPresenter, entryManager); - assertFalse(mDependency.hasInstantiatedDependency(StatusBarWindowManager.class)); + assertFalse(mDependency.hasInstantiatedDependency(StatusBarWindowController.class)); } } 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 8fb2447dab1a..c19188c9b7c0 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 @@ -3,10 +3,7 @@ * * 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 - * + * 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. @@ -16,9 +13,13 @@ package com.android.systemui.statusbar.notification.stack; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; 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.clearInvocations; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -26,6 +27,10 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.Looper; +import android.os.PowerManager; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -33,21 +38,34 @@ 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; +import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationData.Entry; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; -import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager; + +import java.util.ArrayList; 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.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -63,11 +81,18 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Mock private StatusBar mBar; + @Mock private StatusBarStateController mBarState; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationBlockingHelperManager mBlockingHelperManager; @Mock private NotificationGroupManager mGroupManager; @Mock private ExpandHelper mExpandHelper; @Mock private EmptyShadeView mEmptyShadeView; + @Mock private NotificationData mNotificationData; + @Mock private NotificationRemoteInputManager mRemoteInputManager; + @Mock private RemoteInputController mRemoteInputController; + @Mock private SystemServicesProxy mSystemServicesProxy; + private PowerManager mPowerManager; + private TestableNotificationEntryManager mEntryManager; @Before @UiThreadTest @@ -76,9 +101,22 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mDependency.injectTestDependency( NotificationBlockingHelperManager.class, mBlockingHelperManager); + mDependency.injectTestDependency(StatusBarStateController.class, mBarState); + mDependency.injectTestDependency(NotificationRemoteInputManager.class, + mRemoteInputManager); + when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); + + IPowerManager powerManagerService = mock(IPowerManager.class); + mPowerManager = new PowerManager(mContext, powerManagerService, + Handler.createAsync(Looper.myLooper())); + + mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager, + mContext); + mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, null, mNotificationData); + mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); NotificationShelf notificationShelf = spy(new NotificationShelf(getContext(), null)); - mStackScroller = new NotificationStackScrollLayout(getContext()); + mStackScroller = spy(new NotificationStackScrollLayout(getContext())); mStackScroller.setShelf(notificationShelf); mStackScroller.setStatusBar(mBar); mStackScroller.setScrimController(mock(ScrimController.class)); @@ -101,7 +139,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testNotDimmedOnKeyguard() { - when(mBar.getBarState()).thenReturn(StatusBarState.SHADE); + when(mBarState.getState()).thenReturn(StatusBarState.SHADE); mStackScroller.setDimmed(true /* dimmed */, false /* animate */); mStackScroller.setDimmed(true /* dimmed */, true /* animate */); Assert.assertFalse(mStackScroller.isDimmed()); @@ -186,4 +224,98 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(view).setVisible(eq(true), anyBoolean()); verify(view).setSecondaryVisible(eq(true), anyBoolean()); } + + @Test + public void testInflateFooterView() { + mStackScroller.inflateFooterView(); + ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class); + verify(mStackScroller).setFooterView(captor.capture()); + + assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners()); + assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners()); + } + + @Test + public void testUpdateFooter_noNotifications() { + setBarStateForTest(StatusBarState.SHADE); + assertEquals(0, mNotificationData.getActiveNotifications().size()); + + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, false); + } + + @Test + public void testUpdateFooter_remoteInput() { + setBarStateForTest(StatusBarState.SHADE); + ArrayList<Entry> entries = new ArrayList<>(); + entries.add(mock(Entry.class)); + when(mNotificationData.getActiveNotifications()).thenReturn(entries); + + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + when(row.canViewBeDismissed()).thenReturn(true); + when(mStackScroller.getChildCount()).thenReturn(1); + when(mStackScroller.getChildAt(anyInt())).thenReturn(row); + when(mRemoteInputController.isRemoteInputActive()).thenReturn(true); + + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(false, true); + } + + @Test + public void testUpdateFooter_oneClearableNotification() { + setBarStateForTest(StatusBarState.SHADE); + ArrayList<Entry> entries = new ArrayList<>(); + entries.add(mock(Entry.class)); + when(mNotificationData.getActiveNotifications()).thenReturn(entries); + + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + when(row.canViewBeDismissed()).thenReturn(true); + when(mStackScroller.getChildCount()).thenReturn(1); + when(mStackScroller.getChildAt(anyInt())).thenReturn(row); + + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(true, true); + } + + @Test + public void testUpdateFooter_oneNonClearableNotification() { + setBarStateForTest(StatusBarState.SHADE); + ArrayList<Entry> entries = new ArrayList<>(); + entries.add(mock(Entry.class)); + when(mNotificationData.getActiveNotifications()).thenReturn(entries); + + mStackScroller.updateFooter(); + verify(mStackScroller).updateFooterView(true, false); + } + + @Test + public void testUpdateFooter_atEnd() { + // add footer + mStackScroller.inflateFooterView(); + + // add notification + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + when(row.isClearable()).thenReturn(true); + mStackScroller.addContainerView(row); + + mStackScroller.onUpdateRowStates(); + + // move footer to end + verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */)); + } + + @Test + public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() { + clearInvocations(mStackScroller); + mStackScroller.onDensityOrFontScaleChanged(); + verify(mStackScroller).setFooterView(any()); + verify(mStackScroller).setEmptyShadeView(any()); + } + + private void setBarStateForTest(int state) { + ArgumentCaptor<StatusBarStateController.StateListener> captor = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); + verify(mBarState).addListener(captor.capture()); + captor.getValue().onStateChanged(state); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt new file mode 100644 index 000000000000..0d13e975e56a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt @@ -0,0 +1,60 @@ +/* + * 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.phone + +import android.support.test.filters.SmallTest +import android.testing.AndroidTestingRunner +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class ConfigurationControllerImplTest : SysuiTestCase() { + + private val mConfigurationController = + com.android.systemui.statusbar.phone.ConfigurationControllerImpl(mContext) + + @Test + fun testThemeChange() { + val listener = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener) + + mConfigurationController.notifyThemeChanged() + verify(listener).onThemeChanged() + } + + @Test + fun testRemoveListenerDuringCallback() { + val listener = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener) + val listener2 = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener2) + + doAnswer { + mConfigurationController.removeCallback(listener2) + null + }.`when`(listener).onThemeChanged() + + mConfigurationController.notifyThemeChanged() + verify(listener).onThemeChanged() + verify(listener2, never()).onThemeChanged() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 6933328d1893..be4560b5b845 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -68,7 +68,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(StatusBarWindowManager.class); + mDependency.injectMockDependency(StatusBarWindowController.class); mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(getContext(), mViewMediatorCallback, mLockPatternUtils); mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer, 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 e39238d13d36..cbba251c8895 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 @@ -72,11 +72,11 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.AppOpsListener; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationData.Entry; @@ -92,7 +92,6 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.RemoteInputController; -import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -104,7 +103,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -137,6 +135,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; + @Mock private StatusBarStateController mStatusBarStateController; private TestableStatusBar mStatusBar; private FakeMetricsLogger mMetricsLogger; @@ -158,6 +157,7 @@ public class StatusBarTest extends SysuiTestCase { mDependency.injectTestDependency(NotificationListener.class, mNotificationListener); mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class)); mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class)); + mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); @@ -204,7 +204,7 @@ public class StatusBarTest extends SysuiTestCase { mEntryManager, mScrimController, mBiometricUnlockController, mock(ActivityLaunchAnimator.class), mKeyguardViewMediator, mRemoteInputManager, mock(NotificationGroupManager.class), - mock(FalsingManager.class), mock(StatusBarWindowManager.class), + mock(FalsingManager.class), mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class), mock(DozeScrimController.class), mock(NotificationShelf.class), mLockscreenUserManager, mock(CommandQueue.class)); @@ -561,7 +561,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.mState = StatusBarState.KEYGUARD; when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn( new SparseArray<>()); - mStatusBar.updateKeyguardState(false, false); + mStatusBar.onStateChanged(StatusBarState.SHADE); } @Test @@ -590,85 +590,7 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testInflateFooterView() { - mStatusBar.inflateFooterView(); - ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class); - verify(mStackScroller).setFooterView(captor.capture()); - - assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners()); - assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners()); - } - - @Test - public void testUpdateFooter_noNotifications() { - mStatusBar.setBarStateForTest(StatusBarState.SHADE); - assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size()); - - mStatusBar.updateFooter(); - verify(mStackScroller).updateFooterView(false, false); - } - - @Test - public void testUpdateFooter_remoteInput() { - mStatusBar.setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); - when(mNotificationData.getActiveNotifications()).thenReturn(entries); - - ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - when(row.canViewBeDismissed()).thenReturn(true); - when(mStackScroller.getChildCount()).thenReturn(1); - when(mStackScroller.getChildAt(anyInt())).thenReturn(row); - when(mRemoteInputController.isRemoteInputActive()).thenReturn(true); - - mStatusBar.updateFooter(); - verify(mStackScroller).updateFooterView(false, true); - } - - @Test - public void testUpdateFooter_oneClearableNotification() { - mStatusBar.setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); - when(mNotificationData.getActiveNotifications()).thenReturn(entries); - - ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - when(row.canViewBeDismissed()).thenReturn(true); - when(mStackScroller.getChildCount()).thenReturn(1); - when(mStackScroller.getChildAt(anyInt())).thenReturn(row); - - mStatusBar.updateFooter(); - verify(mStackScroller).updateFooterView(true, true); - } - - @Test - public void testUpdateFooter_oneNonClearableNotification() { - mStatusBar.setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); - when(mNotificationData.getActiveNotifications()).thenReturn(entries); - - mStatusBar.updateFooter(); - verify(mStackScroller).updateFooterView(true, false); - } - - @Test - public void testUpdateFooter_atEnd() { - // add footer - mStatusBar.inflateFooterView(); - // add notification - ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - when(row.isClearable()).thenReturn(true); - mStackScroller.addContainerView(row); - - mStatusBar.onUpdateRowStates(); - - // move footer to end - verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */)); - } - - @Test public void testSetState_changesIsFullScreenUserSwitcherState() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); assertFalse(mStatusBar.isFullScreenUserSwitcherState()); @@ -685,20 +607,13 @@ public class StatusBarTest extends SysuiTestCase { // By default, showKeyguardImpl sets state to KEYGUARD. mStatusBar.showKeyguardImpl(); - assertTrue(mStatusBar.mState == StatusBarState.KEYGUARD); + verify(mStatusBarStateController).setState(eq(StatusBarState.KEYGUARD)); // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER. mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class); when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); mStatusBar.showKeyguardImpl(); - assertTrue(mStatusBar.mState == StatusBarState.FULLSCREEN_USER_SWITCHER); - } - - @Test - public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() { - mStatusBar.onDensityOrFontScaleChanged(); - verify(mStackScroller).setFooterView(any()); - verify(mStackScroller).setEmptyShadeView(any()); + verify(mStatusBarStateController).setState(eq(StatusBarState.FULLSCREEN_USER_SWITCHER)); } static class TestableStatusBar extends StatusBar { @@ -716,7 +631,7 @@ public class StatusBarTest extends SysuiTestCase { NotificationRemoteInputManager notificationRemoteInputManager, NotificationGroupManager notificationGroupManager, FalsingManager falsingManager, - StatusBarWindowManager statusBarWindowManager, + StatusBarWindowController statusBarWindowController, NotificationIconAreaController notificationIconAreaController, DozeScrimController dozeScrimController, NotificationShelf notificationShelf, @@ -740,11 +655,10 @@ public class StatusBarTest extends SysuiTestCase { mBiometricUnlockController = biometricUnlockController; mActivityLaunchAnimator = launchAnimator; mKeyguardViewMediator = keyguardViewMediator; - mClearAllEnabled = true; mRemoteInputManager = notificationRemoteInputManager; mGroupManager = notificationGroupManager; mFalsingManager = falsingManager; - mStatusBarWindowManager = statusBarWindowManager; + mStatusBarWindowController = statusBarWindowController; mNotificationIconAreaController = notificationIconAreaController; mDozeScrimController = dozeScrimController; mNotificationShelf = notificationShelf; @@ -774,7 +688,7 @@ public class StatusBarTest extends SysuiTestCase { } - private class TestableNotificationEntryManager extends NotificationEntryManager { + public static class TestableNotificationEntryManager extends NotificationEntryManager { public TestableNotificationEntryManager(SystemServicesProxy systemServicesProxy, PowerManager powerManager, Context context) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java new file mode 100644 index 000000000000..f8223f61edb4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java @@ -0,0 +1,86 @@ +/* + * 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.phone; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.IActivityManager; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; +import android.view.WindowManager; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class StatusBarWindowControllerTest extends SysuiTestCase { + + @Mock + private WindowManager mWindowManager; + @Mock + private DozeParameters mDozeParameters; + @Mock + private View mStatusBarView; + @Mock + private IActivityManager mActivityManager; + + private StatusBarWindowController mStatusBarWindowController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mDozeParameters.getAlwaysOn()).thenReturn(true); + + mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, + mActivityManager, mDozeParameters); + mStatusBarWindowController.add(mStatusBarView, 100 /* height */); + } + + @Test + public void testSetDozing_hidesSystemOverlays() { + mStatusBarWindowController.setDozing(true); + ArgumentCaptor<WindowManager.LayoutParams> captor = + ArgumentCaptor.forClass(WindowManager.LayoutParams.class); + verify(mWindowManager).updateViewLayout(any(), captor.capture()); + int flag = captor.getValue().privateFlags + & WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + assertThat(flag).isNotEqualTo(0); + + reset(mWindowManager); + mStatusBarWindowController.setDozing(false); + verify(mWindowManager).updateViewLayout(any(), captor.capture()); + flag = captor.getValue().privateFlags + & WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + assertThat(flag).isEqualTo(0); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java index 33705e56410f..445a194155bb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java @@ -26,9 +26,11 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.MotionEvent; +import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Before; import org.junit.Test; @@ -44,6 +46,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase { @Before public void setUp() { + mDependency.injectMockDependency(StatusBarStateController.class); mView = new StatusBarWindowView(getContext(), null); mStatusBar = mock(StatusBar.class); mView.setService(mStatusBar); @@ -53,7 +56,8 @@ public class StatusBarWindowViewTest extends SysuiTestCase { @Test public void testDragDownHelperCalledWhenDraggingDown() throws Exception { - when(mStatusBar.getBarState()).thenReturn(StatusBarState.SHADE); + when(Dependency.get(StatusBarStateController.class).getState()) + .thenReturn(StatusBarState.SHADE); when(mDragDownHelper.isDraggingDown()).thenReturn(true); long now = SystemClock.elapsedRealtime(); MotionEvent ev = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0 /* x */, 0 /* y */, diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java index 9ef30c3d1859..5ddf7a208379 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java @@ -23,4 +23,8 @@ public class FakeConfigurationController public FakeConfigurationController(LeakCheckedTest.SysuiLeakCheck sysuiLeakCheck) { super(sysuiLeakCheck, "config"); } + + @Override + public void notifyThemeChanged() { + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java index 3f952c3cbca9..51b86c26dff2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java @@ -72,6 +72,11 @@ public class FakeKeyguardMonitor implements KeyguardMonitor { } @Override + public long calculateGoingToFullShadeDelay() { + return 0; + } + + @Override public boolean canSkipBouncer() { return false; } diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml index 754ba722d081..b08924b8adb6 100644 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml @@ -16,7 +16,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay">Corner display cutout</string> + <string name="display_cutout_emulation_overlay">Corner cutout</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml index 68c2dcbbe3f6..0a106fa0c08f 100644 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml @@ -16,7 +16,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay">Double display cutout</string> + <string name="display_cutout_emulation_overlay">Double cutout</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml index 49896773ac55..0bf83306f875 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml @@ -18,7 +18,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay">Narrow display cutout</string> + <string name="display_cutout_emulation_overlay">Narrow cutout</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml index 6dcbbd923601..bcc7c9756a6e 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml @@ -16,7 +16,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay">Tall display cutout</string> + <string name="display_cutout_emulation_overlay">Tall cutout</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml index f4b9f7ea7c37..0fcbdebbd345 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml @@ -16,7 +16,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay">Wide display cutout</string> + <string name="display_cutout_emulation_overlay">Wide cutout</string> </resources> diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index acbb67c29bb2..6be95500adcb 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1567,8 +1567,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } final long identity = Binder.clearCallingIdentity(); try { + final String settingValue = builder.toString(); Settings.Secure.putStringForUser(mContext.getContentResolver(), - settingName, builder.toString(), userId); + settingName, TextUtils.isEmpty(settingValue) ? null : settingValue, userId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 6f03b762254b..5771748d6ea3 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -438,8 +438,13 @@ public final class AutofillManagerService extends SystemService { Slog.i(TAG, "setLogLevel(): " + level); mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AUTOFILL_LOGGING_LEVEL, level); + final long token = Binder.clearCallingIdentity(); + try { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.AUTOFILL_LOGGING_LEVEL, level); + } finally { + Binder.restoreCallingIdentity(token); + } } private void setLogLevelFromSettings() { @@ -492,8 +497,13 @@ public final class AutofillManagerService extends SystemService { mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); Slog.i(TAG, "setMaxPartitions(): " + max); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max); + final long token = Binder.clearCallingIdentity(); + try { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max); + } finally { + Binder.restoreCallingIdentity(token); + } } private void setMaxPartitionsFromSettings() { @@ -521,8 +531,13 @@ public final class AutofillManagerService extends SystemService { mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); Slog.i(TAG, "setMaxVisibleDatasets(): " + max); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, max); + final long token = Binder.clearCallingIdentity(); + try { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, max); + } finally { + Binder.restoreCallingIdentity(token); + } } private void setMaxVisibleDatasetsFromSettings() { diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index b3f6bd1d41cc..998e441f67d8 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -45,8 +45,10 @@ import android.os.ServiceManager; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.provider.Settings; import android.util.ArrayMap; @@ -657,33 +659,35 @@ public class AppOpsService extends IAppOpsService.Stub { } }); - StorageManagerInternal storageManagerInternal = LocalServices.getService( - StorageManagerInternal.class); - storageManagerInternal.addExternalStoragePolicy( - new StorageManagerInternal.ExternalStorageMountPolicy() { - @Override - public int getMountMode(int uid, String packageName) { - if (Process.isIsolated(uid)) { - return Zygote.MOUNT_EXTERNAL_NONE; - } - if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, - packageName) != AppOpsManager.MODE_ALLOWED) { - return Zygote.MOUNT_EXTERNAL_NONE; - } - if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, - packageName) != AppOpsManager.MODE_ALLOWED) { - return Zygote.MOUNT_EXTERNAL_READ; + if (!SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + storageManagerInternal.addExternalStoragePolicy( + new StorageManagerInternal.ExternalStorageMountPolicy() { + @Override + public int getMountMode(int uid, String packageName) { + if (Process.isIsolated(uid)) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_READ; + } + return Zygote.MOUNT_EXTERNAL_WRITE; } - return Zygote.MOUNT_EXTERNAL_WRITE; - } - @Override - public boolean hasExternalStorage(int uid, String packageName) { - final int mountMode = getMountMode(uid, packageName); - return mountMode == Zygote.MOUNT_EXTERNAL_READ - || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; - } - }); + @Override + public boolean hasExternalStorage(int uid, String packageName) { + final int mountMode = getMountMode(uid, packageName); + return mountMode == Zygote.MOUNT_EXTERNAL_READ + || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; + } + }); + } } public void packageRemoved(int uid, String packageName) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 784dfb4d0cec..02a62ff591be 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -1714,10 +1714,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void addClient(IInputMethodClient client, - IInputContext inputContext, int uid, int pid) { - if (!calledFromValidUser()) { - return; + public void addClient(IInputMethodClient client, IInputContext inputContext, int uid, int pid) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Only system process can call this method."); } synchronized (mMethodMap) { mClients.put(client.asBinder(), new ClientState(client, @@ -1727,8 +1726,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void removeClient(IInputMethodClient client) { - if (!calledFromValidUser()) { - return; + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Only system process can call this method."); } synchronized (mMethodMap) { ClientState cs = mClients.remove(client.asBinder()); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 4b0379ef75c1..d8296023383c 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1227,25 +1227,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub public boolean getIpForwardingEnabled() throws IllegalStateException{ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - final NativeDaemonEvent event; try { - event = mConnector.execute("ipfwd", "status"); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + final boolean isEnabled = mNetdService.ipfwdEnabled(); + return isEnabled; + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); } - - // 211 Forwarding enabled - event.checkCode(IpFwdStatusResult); - return event.getMessage().endsWith("enabled"); } @Override public void setIpForwardingEnabled(boolean enable) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { - mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering"); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + if (enable) { + mNetdService.ipfwdEnableForwarding("tethering"); + } else { + mNetdService.ipfwdDisableForwarding("tethering"); + } + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); } } @@ -1371,11 +1371,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub } private void modifyInterfaceForward(boolean add, String fromIface, String toIface) { - final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface); try { - mConnector.execute(cmd); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + if (add) { + mNetdService.ipfwdAddInterfaceForward(fromIface, toIface); + } else { + mNetdService.ipfwdRemoveInterfaceForward(fromIface, toIface); + } + } 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 306cd832e8ef..1746b857cf5c 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3867,5 +3867,29 @@ class StorageManagerService extends IStorageManager.Stub } return true; } + + @Override + public void mountExternalStorageForApp(String packageName, int appId, String sharedUserId, + int userId) { + final String sandboxId; + synchronized (mPackagesLock) { + final ArraySet<String> userPackages = getPackagesForUserPL(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)) { + return; + } + userPackages.add(packageName); + mAppIds.put(packageName, appId); + sandboxId = getSandboxId(packageName, sharedUserId); + mSandboxIds.put(appId, sandboxId); + } + + try { + mVold.mountExternalStorageForApp(packageName, appId, sandboxId, userId); + } catch (Exception e) { + Slog.wtf(TAG, e); + } + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1d01a572bbfb..a8269824da0e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15466,12 +15466,6 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized(this) { // !!! TODO: currently no check here that we're already bound - BatteryStatsImpl.Uid.Pkg.Serv ss = null; - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - synchronized (stats) { - ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name); - } - // Backup agent is now in use, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( @@ -15482,7 +15476,7 @@ public class ActivityManagerService extends IActivityManager.Stub + app.packageName + ": " + e); } - BackupRecord r = new BackupRecord(ss, app, backupMode); + BackupRecord r = new BackupRecord(app, backupMode); ComponentName hostingName = (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL) ? new ComponentName(app.packageName, app.backupAgentName) diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java index 5fa7e6a37133..40ad383e7d58 100644 --- a/services/core/java/com/android/server/am/BackupRecord.java +++ b/services/core/java/com/android/server/am/BackupRecord.java @@ -16,8 +16,6 @@ package com.android.server.am; -import com.android.internal.os.BatteryStatsImpl; - import android.content.pm.ApplicationInfo; /** @hide */ @@ -28,7 +26,6 @@ final class BackupRecord { public static final int RESTORE = 2; public static final int RESTORE_FULL = 3; - final BatteryStatsImpl.Uid.Pkg.Serv stats; String stringName; // cached toString() output final ApplicationInfo appInfo; // information about BackupAgent's app final int backupMode; // full backup / incremental / restore @@ -36,9 +33,7 @@ final class BackupRecord { // ----- Implementation ----- - BackupRecord(BatteryStatsImpl.Uid.Pkg.Serv _agentStats, ApplicationInfo _appInfo, - int _backupMode) { - stats = _agentStats; + BackupRecord(ApplicationInfo _appInfo, int _backupMode) { appInfo = _appInfo; backupMode = _backupMode; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 75b3556f9206..0eff7f57895b 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -151,6 +151,8 @@ public final class DisplayManagerService extends SystemService { // Otherwise WFD is enabled according to the value of config_enableWifiDisplay. private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable"; + private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top"; + private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000; private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1; @@ -243,6 +245,15 @@ public final class DisplayManagerService extends SystemService { // device). private Point mStableDisplaySize = new Point(); + // Whether the system has finished booting or not. + private boolean mSystemReady; + + // The top inset of the default display. + // This gets persisted so that the boot animation knows how to transition from the display's + // full size to the size configured by the user. Right now we only persist and animate the top + // inset, but theoretically we could do it for all of them. + private int mDefaultDisplayTopInset; + // Viewports of the default display and the display that should receive touch // input from an external source. Used by the input system. private final DisplayViewport mDefaultViewport = new DisplayViewport(); @@ -301,6 +312,7 @@ public final class DisplayManagerService extends SystemService { Resources resources = mContext.getResources(); mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger( com.android.internal.R.integer.config_defaultDisplayDefaultColorMode); + mDefaultDisplayTopInset = SystemProperties.getInt(PROP_DEFAULT_DISPLAY_TOP_INSET, -1); float[] lux = getFloatArray(resources.obtainTypedArray( com.android.internal.R.array.config_minimumBrightnessCurveLux)); float[] nits = getFloatArray(resources.obtainTypedArray( @@ -311,6 +323,8 @@ public final class DisplayManagerService extends SystemService { PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting(); mCurrentUserId = UserHandle.USER_SYSTEM; + + mSystemReady = false; } public void setupSchedulerPolicies() { @@ -400,6 +414,10 @@ public final class DisplayManagerService extends SystemService { synchronized (mSyncRoot) { mSafeMode = safeMode; mOnlyCore = onlyCore; + mSystemReady = true; + // Just in case the top inset changed before the system was ready. At this point, any + // relevant configuration should be in place. + recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY)); } mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); @@ -457,7 +475,7 @@ public final class DisplayManagerService extends SystemService { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display != null) { if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) { - sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + handleLogicalDisplayChanged(displayId, display); scheduleTraversalLocked(false); } } @@ -938,6 +956,13 @@ public final class DisplayManagerService extends SystemService { scheduleTraversalLocked(false); } + private void handleLogicalDisplayChanged(int displayId, @NonNull LogicalDisplay display) { + if (displayId == Display.DEFAULT_DISPLAY) { + recordTopInsetLocked(display); + } + sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + } + private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { @@ -991,6 +1016,7 @@ public final class DisplayManagerService extends SystemService { configureColorModeLocked(display, device); if (isDefault) { recordStableDisplayStatsIfNeededLocked(display); + recordTopInsetLocked(display); } mLogicalDisplays.put(displayId, display); @@ -1039,6 +1065,21 @@ public final class DisplayManagerService extends SystemService { } } + private void recordTopInsetLocked(@Nullable LogicalDisplay d) { + // We must only persist the inset after boot has completed, otherwise we will end up + // overwriting the persisted value before the masking flag has been loaded from the + // resource overlay. + if (!mSystemReady || d == null) { + return; + } + int topInset = d.getInsets().top; + if (topInset == mDefaultDisplayTopInset) { + return; + } + mDefaultDisplayTopInset = topInset; + SystemProperties.set(PROP_DEFAULT_DISPLAY_TOP_INSET, Integer.toString(topInset)); + } + private void setStableDisplaySizeLocked(int width, int height) { mStableDisplaySize = new Point(width, height); try { @@ -1118,7 +1159,7 @@ public final class DisplayManagerService extends SystemService { sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); changed = true; } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { - sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + handleLogicalDisplayChanged(displayId, display); changed = true; } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 373de63c0ec9..5b7c5205ce3a 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -18,6 +18,7 @@ package com.android.server.display; import android.graphics.Rect; import android.hardware.display.DisplayManagerInternal; +import android.os.SystemProperties; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -57,6 +58,8 @@ import java.util.Objects; * </p> */ final class LogicalDisplay { + private static final String PROP_MASKING_INSET_TOP = "persist.sys.displayinset.top"; + private final DisplayInfo mBaseDisplayInfo = new DisplayInfo(); // The layer stack we use when the display has been blanked to prevent any @@ -297,6 +300,17 @@ final class LogicalDisplay { } /** + * Return the insets currently applied to the display. + * + * Note that the base DisplayInfo already takes these insets into account, so if you want to + * find out the <b>true</b> size of the display, you need to add them back to the logical + * dimensions. + */ + public Rect getInsets() { + return getMaskingInsets(mPrimaryDisplayDeviceInfo); + } + + /** * Returns insets in ROTATION_0 for areas that are masked. */ private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 14af15f0a3fd..3845954bc0d4 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -19,12 +19,16 @@ import static com.android.server.hdmi.Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_P import static com.android.server.hdmi.Constants.PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON; +import android.annotation.Nullable; import android.hardware.hdmi.HdmiDeviceInfo; +import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.os.SystemProperties; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.hdmi.Constants.AudioCodec; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; /** @@ -48,8 +52,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // Whether ARC is available or not. "true" means that ARC is established between TV and // AVR as audio receiver. - @ServiceThreadOnly - private boolean mArcEstablished = false; + @ServiceThreadOnly private boolean mArcEstablished = false; protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); @@ -218,12 +221,56 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRequestShortAudioDescriptor(HdmiCecMessage message) { assertRunOnServiceThread(); - // TODO(b/80297701): implement request short audio descriptor HdmiLogger.debug(TAG + "Stub handleRequestShortAudioDescriptor"); - mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); + if (!isSystemAudioControlFeatureEnabled()) { + mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); + return true; + } + if (!isSystemAudioActivated()) { + mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); + return true; + } + AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo(); + if (deviceInfo == null) { + mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE); + return true; + } + @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams()); + byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes); + if (sadBytes.length == 0) { + mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); + } else { + mService.sendCecCommand( + HdmiCecMessageBuilder.buildReportShortAudioDescriptor( + mAddress, message.getSource(), sadBytes)); + } return true; } + private byte[] getSupportedShortAudioDescriptors( + AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) { + // TODO(b/80297701) implement + return new byte[] {}; + } + + @Nullable + private AudioDeviceInfo getSystemAudioDeviceInfo() { + // TODO(b/80297701) implement + // Get the audio device used for system audio mode. + return null; + } + + @AudioCodec + private int[] parseAudioFormatCodes(byte[] params) { + @AudioCodec int[] audioFormatCodes = new int[params.length]; + for (int i = 0; i < params.length; i++) { + byte val = params[i]; + audioFormatCodes[i] = + val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE; + } + return audioFormatCodes; + } + @Override @ServiceThreadOnly protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) { @@ -274,23 +321,19 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mArcEstablished = enabled; } - /** - * Switch hardware ARC circuit in the system. - */ + /** Switch hardware ARC circuit in the system. */ @ServiceThreadOnly private void enableAudioReturnChannel(boolean enabled) { assertRunOnServiceThread(); mService.enableAudioReturnChannel( - SystemProperties.getInt( - Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), + SystemProperties.getInt(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, 0), enabled); } private void notifyArcStatusToAudioService(boolean enabled) { // Note that we don't set any name to ARC. - mService.getAudioManager().setWiredDeviceConnectionState( - AudioSystem.DEVICE_IN_HDMI, - enabled ? 1 : 0, "", ""); + mService.getAudioManager() + .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", ""); } private void reportAudioStatus(HdmiCecMessage message) { @@ -323,8 +366,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; - if (newSystemAudioMode && - !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { + if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { switchToAudioInput(); } // TODO(b/80297700): Mute device when TV terminates the system audio control @@ -340,9 +382,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { /** * Method to check if the target device belongs to the subtree of the current device or not. + * * <p>Return true if it does or if the two devices share the same physical address. * * <p>This check assumes both device physical address and target address are valid. + * * @param targetPhysicalAddress is the physical address of the target device */ protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { @@ -352,9 +396,9 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { // or if they only differs for one byte, but not the first byte, // and myPhysicalAddress is 0 after that byte if (xor == 0 - || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) - || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) - || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { + || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) + || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) + || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { return true; } return false; @@ -374,7 +418,15 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); } - protected boolean isSystemAudioControlFeatureEnabled() { + @ServiceThreadOnly + void setSystemAudioControlFeatureEnabled(boolean enabled) { + assertRunOnServiceThread(); + synchronized (mLock) { + mSystemAudioControlFeatureEnabled = enabled; + } + } + + boolean isSystemAudioControlFeatureEnabled() { synchronized (mLock) { return mSystemAudioControlFeatureEnabled; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 649a2da1c451..941c321d484a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -16,9 +16,10 @@ package com.android.server.hdmi; +import com.android.server.hdmi.Constants.AudioCodec; + import java.io.UnsupportedEncodingException; import java.util.Arrays; -import com.android.server.hdmi.Constants.AudioCodec; /** * A helper class to build {@link HdmiCecMessage} from various cec commands. @@ -452,6 +453,19 @@ public class HdmiCecMessageBuilder { } /** + * Build <Report Short Audio Descriptor> command. + * + * @param src source address of command + * @param des destination address of command + * @param sadBytes Short Audio Descriptor in bytes + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) { + // TODO(b/80297701) validate. + return buildCommand(src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes); + } + + /** * Build <Give Audio Status> command. * * @param src source address of command diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index a2eb1c1b141f..c16d3cd5b4a5 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -402,6 +402,8 @@ public class HdmiControlService extends SystemService { if (mCecController != null) { if (mHdmiControlEnabled) { initializeCec(INITIATED_BY_BOOT_UP); + } else { + mCecController.setOption(OptionKey.ENABLE_CEC, false); } } else { Slog.i(TAG, "Device does not support HDMI-CEC."); @@ -2384,6 +2386,7 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private void enableHdmiControlService() { + mCecController.setOption(OptionKey.ENABLE_CEC, true); mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED); @@ -2400,6 +2403,7 @@ public class HdmiControlService extends SystemService { @Override public void run() { mCecController.setOption(OptionKey.ENABLE_CEC, false); + mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false); mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED); clearLocalDevices(); } diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 8be8450b3413..decdac6cbfce 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -30,6 +30,7 @@ public interface NotificationDelegate { void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv); void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index dd3e2d42ef88..ce71dd2ec9ad 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -700,7 +700,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) { + public void onNotificationClick(int callingUid, int callingPid, String key, + NotificationVisibility nv) { exitIdle(); synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); @@ -757,11 +758,13 @@ public class NotificationManagerService extends SystemService { public void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, NotificationVisibility nv) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { r.recordDismissalSurface(dismissalSurface); + r.recordDismissalSentiment(dismissalSentiment); } } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, @@ -797,8 +800,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, - int uid, int initialPid, String message, int userId) { + public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, + int id, int uid, int initialPid, String message, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); } @@ -1040,10 +1043,12 @@ public class NotificationManagerService extends SystemService { uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); cancelNotifications = false; hideNotifications = true; } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); cancelNotifications = false; unhideNotifications = true; } else if (queryRestart) { @@ -5964,6 +5969,7 @@ public class NotificationManagerService extends SystemService { } notificationList.remove(i); mNotificationsByKey.remove(r.getKey()); + r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); canceledNotifications.add(r); cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index a6d861565080..fbb42ea160da 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -1065,6 +1065,10 @@ public final class NotificationRecord { mStats.setDismissalSurface(surface); } + public void recordDismissalSentiment(@NotificationStats.DismissalSentiment int sentiment) { + mStats.setDismissalSentiment(sentiment); + } + public void recordSnoozed() { mStats.setSnoozed(); } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index f082271ab094..c73870189002 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -22,11 +22,14 @@ import static android.content.Intent.ACTION_PACKAGE_CHANGED; import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.ACTION_USER_ADDED; import static android.content.Intent.ACTION_USER_REMOVED; +import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.SIGNATURE_MATCH; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityThread; import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -34,6 +37,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManagerInternal; @@ -269,13 +273,30 @@ public final class OverlayManagerService extends SystemService { @Override public void onBootPhase(int phase) { - if (phase == PHASE_SYSTEM_SERVICES_READY) { + if (phase == PHASE_SYSTEM_SERVICES_READY && mInitCompleteSignal != null) { ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal, "Wait for OverlayManagerService init"); mInitCompleteSignal = null; } } + public void updateSystemUiContext() { + if (mInitCompleteSignal != null) { + ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal, + "Wait for OverlayManagerService init"); + mInitCompleteSignal = null; + } + + final ApplicationInfo ai; + try { + ai = mPackageManager.mPackageManager.getApplicationInfo("android", + GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai); + } + private void initIfNeeded() { final UserManager um = getContext().getSystemService(UserManager.class); final List<UserInfo> users = um.getUsers(true /*excludeDying*/); diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java new file mode 100644 index 000000000000..7d762d98e6f6 --- /dev/null +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -0,0 +1,1878 @@ +/* + * 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.pm; + +import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; +import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD; + +import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; +import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; +import static com.android.server.pm.PackageManagerService.fixProcessName; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.AuxiliaryResolveInfo; +import android.content.pm.InstantAppResolveInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.ActivityIntentInfo; +import android.content.pm.PackageParser.ServiceIntentInfo; +import android.content.pm.PackageUserState; +import android.content.pm.ProviderInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; +import android.util.LogPrinter; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.IntentResolver; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Resolves all Android component types [activities, services, providers and receivers]. */ +public class ComponentResolver { + private static final String TAG = "PackageManager"; + private static final boolean DEBUG_FILTERS = false; + private static final boolean DEBUG_SHOW_INFO = false; + + /** + * The set of all protected actions [i.e. those actions for which a high priority + * intent filter is disallowed]. + */ + private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>(); + static { + PROTECTED_ACTIONS.add(Intent.ACTION_SEND); + PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO); + PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE); + PROTECTED_ACTIONS.add(Intent.ACTION_VIEW); + } + + static final Comparator<ResolveInfo> RESOLVE_PRIORITY_SORTER = (r1, r2) -> { + int v1 = r1.priority; + int v2 = r2.priority; + //System.out.println("Comparing: q1=" + q1 + " q2=" + q2); + if (v1 != v2) { + return (v1 > v2) ? -1 : 1; + } + v1 = r1.preferredOrder; + v2 = r2.preferredOrder; + if (v1 != v2) { + return (v1 > v2) ? -1 : 1; + } + if (r1.isDefault != r2.isDefault) { + return r1.isDefault ? -1 : 1; + } + v1 = r1.match; + v2 = r2.match; + //System.out.println("Comparing: m1=" + m1 + " m2=" + m2); + if (v1 != v2) { + return (v1 > v2) ? -1 : 1; + } + if (r1.system != r2.system) { + return r1.system ? -1 : 1; + } + if (r1.activityInfo != null) { + return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName); + } + if (r1.serviceInfo != null) { + return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName); + } + if (r1.providerInfo != null) { + return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName); + } + return 0; + }; + + private static UserManagerService sUserManager; + private static PackageManagerInternal sPackageManagerInternal; + + /** + * Locking within package manager is going to get worse before it gets better. Currently, + * we need to share the {@link PackageManagerService} lock to prevent deadlocks. This occurs + * because in order to safely query the resolvers, we need to obtain this lock. However, + * during resolution, we call into the {@link PackageManagerService}. This is _not_ to + * operate on data controlled by the service proper, but, to check the state of package + * settings [contained in a {@link Settings} object]. However, the {@link Settings} object + * happens to be protected by the main {@link PackageManagerService} lock. + * <p> + * There are a couple potential solutions. + * <ol> + * <li>Split all of our locks into reader/writer locks. This would allow multiple, + * simultaneous read operations and means we don't have to be as cautious about lock + * layering. Only when we want to perform a write operation will we ever be in a + * position to deadlock the system.</li> + * <li>Use the same lock across all classes within the {@code com.android.server.pm} + * package. By unifying the lock object, we remove any potential lock layering issues + * within the package manager. However, we already have a sense that this lock is + * heavily contended and merely adding more dependencies on it will have further + * impact.</li> + * <li>Implement proper lock ordering within the package manager. By defining the + * relative layer of the component [eg. {@link PackageManagerService} is at the top. + * Somewhere in the middle would be {@link ComponentResolver}. At the very bottom + * would be {@link Settings}.] The ordering would allow higher layers to hold their + * lock while calling down. Lower layers must relinquish their lock before calling up. + * Since {@link Settings} would live at the lowest layer, the {@link ComponentResolver} + * would be able to hold its lock while checking the package setting state.</li> + * </ol> + */ + private final Object mLock; + + /** All available activities, for your resolving pleasure. */ + @GuardedBy("mLock") + private final ActivityIntentResolver mActivities = new ActivityIntentResolver(); + + /** All available providers, for your resolving pleasure. */ + @GuardedBy("mLock") + private final ProviderIntentResolver mProviders = new ProviderIntentResolver(); + + /** All available receivers, for your resolving pleasure. */ + @GuardedBy("mLock") + private final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); + + /** All available services, for your resolving pleasure. */ + @GuardedBy("mLock") + private final ServiceIntentResolver mServices = new ServiceIntentResolver(); + + /** Mapping from provider authority [first directory in content URI codePath) to provider. */ + @GuardedBy("mLock") + private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>(); + + /** Whether or not processing protected filters should be deferred. */ + private boolean mDeferProtectedFilters = true; + + /** + * Tracks high priority intent filters for protected actions. During boot, certain + * filter actions are protected and should never be allowed to have a high priority + * intent filter for them. However, there is one, and only one exception -- the + * setup wizard. It must be able to define a high priority intent filter for these + * actions to ensure there are no escapes from the wizard. We need to delay processing + * of these during boot as we need to inspect at all of the intent filters on the + * /system partition in order to know which component is the setup wizard. This can + * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}. + */ + private List<PackageParser.ActivityIntentInfo> mProtectedFilters; + + ComponentResolver(UserManagerService userManager, + PackageManagerInternal packageManagerInternal, + Object lock) { + sPackageManagerInternal = packageManagerInternal; + sUserManager = userManager; + mLock = lock; + } + + /** Returns the given activity */ + PackageParser.Activity getActivity(ComponentName component) { + synchronized (mLock) { + return mActivities.mActivities.get(component); + } + } + + /** Returns the given provider */ + PackageParser.Provider getProvider(ComponentName component) { + synchronized (mLock) { + return mProviders.mProviders.get(component); + } + } + + /** Returns the given receiver */ + PackageParser.Activity getReceiver(ComponentName component) { + synchronized (mLock) { + return mReceivers.mActivities.get(component); + } + } + + /** Returns the given service */ + PackageParser.Service getService(ComponentName component) { + synchronized (mLock) { + return mServices.mServices.get(component); + } + } + + List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, int userId) { + synchronized (mLock) { + return mActivities.queryIntent(intent, resolvedType, flags, userId); + } + } + + List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, + List<PackageParser.Activity> activities, int userId) { + synchronized (mLock) { + return mActivities.queryIntentForPackage( + intent, resolvedType, flags, activities, userId); + } + } + + List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, int userId) { + synchronized (mLock) { + return mProviders.queryIntent(intent, resolvedType, flags, userId); + } + } + + List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, + List<PackageParser.Provider> providers, int userId) { + synchronized (mLock) { + return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId); + } + } + + List<ProviderInfo> queryProviders(String processName, String metaDataKey, int uid, int flags, + int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + List<ProviderInfo> providerList = null; + synchronized (mLock) { + for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) { + final PackageParser.Provider p = mProviders.mProviders.valueAt(i); + final PackageSetting ps = (PackageSetting) p.owner.mExtras; + if (ps == null) { + continue; + } + if (p.info.authority == null) { + continue; + } + if (processName != null && (!p.info.processName.equals(processName) + || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) { + continue; + } + // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter. + if (metaDataKey != null + && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) { + continue; + } + final ProviderInfo info = PackageParser.generateProviderInfo( + p, flags, ps.readUserState(userId), userId); + if (info == null) { + continue; + } + if (providerList == null) { + providerList = new ArrayList<>(i + 1); + } + providerList.add(info); + } + } + return providerList; + } + + ProviderInfo queryProvider(String authority, int flags, int userId) { + synchronized (mLock) { + final PackageParser.Provider p = mProvidersByAuthority.get(authority); + if (p == null) { + return null; + } + final PackageSetting ps = (PackageSetting) p.owner.mExtras; + if (ps == null) { + return null; + } + return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId); + } + } + + void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo, boolean safeMode, + int userId) { + synchronized (mLock) { + for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) { + final PackageParser.Provider p = mProvidersByAuthority.valueAt(i); + final PackageSetting ps = (PackageSetting) p.owner.mExtras; + if (ps == null) { + continue; + } + if (!p.syncable) { + continue; + } + if (safeMode + && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + continue; + } + final ProviderInfo info = + PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId); + if (info == null) { + continue; + } + outNames.add(mProvidersByAuthority.keyAt(i)); + outInfo.add(info); + } + } + } + + List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, int userId) { + synchronized (mLock) { + return mReceivers.queryIntent(intent, resolvedType, flags, userId); + } + } + + List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, + List<PackageParser.Activity> receivers, int userId) { + synchronized (mLock) { + return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId); + } + } + + List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, int userId) { + synchronized (mLock) { + return mServices.queryIntent(intent, resolvedType, flags, userId); + } + } + + List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, + List<PackageParser.Service> services, int userId) { + synchronized (mLock) { + return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId); + } + } + + /** Returns {@code true} if the given activity is defined by some package */ + boolean isActivityDefined(ComponentName component) { + synchronized (mLock) { + return mActivities.mActivities.get(component) != null; + } + } + + /** Asserts none of the providers defined in the given package haven't already been defined. */ + void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException { + synchronized (mLock) { + assertProvidersNotDefinedLocked(pkg); + } + } + + /** Add all components defined in the given package to the internal structures. */ + void addAllComponents(PackageParser.Package pkg, boolean chatty) { + final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>(); + synchronized (mLock) { + addActivitiesLocked(pkg, newIntents, chatty); + addReceiversLocked(pkg, chatty); + addProvidersLocked(pkg, chatty); + addServicesLocked(pkg, chatty); + } + final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName( + PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM); + for (int i = newIntents.size() - 1; i >= 0; --i) { + final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i); + final PackageParser.Package disabledPkg = sPackageManagerInternal + .getDisabledPackage(intentInfo.activity.info.packageName); + final List<PackageParser.Activity> systemActivities = + disabledPkg != null ? disabledPkg.activities : null; + adjustPriority(systemActivities, intentInfo, setupWizardPackage); + } + } + + /** Removes all components defined in the given package from the internal structures. */ + void removeAllComponents(PackageParser.Package pkg, boolean chatty) { + synchronized (mLock) { + removeAllComponentsLocked(pkg, chatty); + } + } + + /** + * Reprocess any protected filters that have been deferred. At this point, we've scanned + * all of the filters defined on the /system partition and know the special components. + */ + void fixProtectedFilterPriorities() { + if (!mDeferProtectedFilters) { + return; + } + mDeferProtectedFilters = false; + + if (mProtectedFilters == null || mProtectedFilters.size() == 0) { + return; + } + final List<ActivityIntentInfo> protectedFilters = mProtectedFilters; + mProtectedFilters = null; + + final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName( + PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM); + if (DEBUG_FILTERS && setupWizardPackage == null) { + Slog.i(TAG, "No setup wizard;" + + " All protected intents capped to priority 0"); + } + for (int i = protectedFilters.size() - 1; i >= 0; --i) { + final ActivityIntentInfo filter = protectedFilters.get(i); + if (filter.activity.info.packageName.equals(setupWizardPackage)) { + if (DEBUG_FILTERS) { + Slog.i(TAG, "Found setup wizard;" + + " allow priority " + filter.getPriority() + ";" + + " package: " + filter.activity.info.packageName + + " activity: " + filter.activity.className + + " priority: " + filter.getPriority()); + } + // skip setup wizard; allow it to keep the high priority filter + continue; + } + if (DEBUG_FILTERS) { + Slog.i(TAG, "Protected action; cap priority to 0;" + + " package: " + filter.activity.info.packageName + + " activity: " + filter.activity.className + + " origPrio: " + filter.getPriority()); + } + filter.setPriority(0); + } + } + + void dumpActivityResolvers(PrintWriter pw, DumpState dumpState, String packageName) { + if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:" + : "Activity Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + void dumpProviderResolvers(PrintWriter pw, DumpState dumpState, String packageName) { + if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:" + : "Provider Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + void dumpReceiverResolvers(PrintWriter pw, DumpState dumpState, String packageName) { + if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:" + : "Receiver Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + void dumpServiceResolvers(PrintWriter pw, DumpState dumpState, String packageName) { + if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:" + : "Service Resolver Table:", " ", packageName, + dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { + dumpState.setTitlePrinted(true); + } + } + + void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) { + boolean printedSomething = false; + for (PackageParser.Provider p : mProviders.mProviders.values()) { + if (packageName != null && !packageName.equals(p.info.packageName)) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) { + pw.println(); + } + pw.println("Registered ContentProviders:"); + printedSomething = true; + } + pw.print(" "); p.printComponentShortName(pw); pw.println(":"); + pw.print(" "); pw.println(p.toString()); + } + printedSomething = false; + for (Map.Entry<String, PackageParser.Provider> entry : + mProvidersByAuthority.entrySet()) { + PackageParser.Provider p = entry.getValue(); + if (packageName != null && !packageName.equals(p.info.packageName)) { + continue; + } + if (!printedSomething) { + if (dumpState.onTitlePrinted()) { + pw.println(); + } + pw.println("ContentProvider Authorities:"); + printedSomething = true; + } + pw.print(" ["); pw.print(entry.getKey()); pw.println("]:"); + pw.print(" "); pw.println(p.toString()); + if (p.info != null && p.info.applicationInfo != null) { + final String appInfo = p.info.applicationInfo.toString(); + pw.print(" applicationInfo="); pw.println(appInfo); + } + } + } + + void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) { + if (dumpState.onTitlePrinted()) pw.println(); + pw.println("Service permissions:"); + + final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator(); + while (filterIterator.hasNext()) { + final ServiceIntentInfo info = filterIterator.next(); + final ServiceInfo serviceInfo = info.service.info; + final String permission = serviceInfo.permission; + if (permission != null) { + pw.print(" "); + pw.print(serviceInfo.getComponentName().flattenToShortString()); + pw.print(": "); + pw.println(permission); + } + } + } + + @GuardedBy("mLock") + private void addActivitiesLocked(PackageParser.Package pkg, + List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) { + final int activitiesSize = pkg.activities.size(); + StringBuilder r = null; + for (int i = 0; i < activitiesSize; i++) { + PackageParser.Activity a = pkg.activities.get(i); + a.info.processName = + fixProcessName(pkg.applicationInfo.processName, a.info.processName); + mActivities.addActivity(a, "activity", newIntents); + if (DEBUG_PACKAGE_SCANNING && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(a.info.name); + } + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); + } + } + + @GuardedBy("mLock") + private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) { + final int providersSize = pkg.providers.size(); + StringBuilder r = null; + for (int i = 0; i < providersSize; i++) { + PackageParser.Provider p = pkg.providers.get(i); + p.info.processName = fixProcessName(pkg.applicationInfo.processName, + p.info.processName); + mProviders.addProvider(p); + p.syncable = p.info.isSyncable; + if (p.info.authority != null) { + String[] names = p.info.authority.split(";"); + p.info.authority = null; + for (int j = 0; j < names.length; j++) { + if (j == 1 && p.syncable) { + // We only want the first authority for a provider to possibly be + // syncable, so if we already added this provider using a different + // authority clear the syncable flag. We copy the provider before + // changing it because the mProviders object contains a reference + // to a provider that we don't want to change. + // Only do this for the second authority since the resulting provider + // object can be the same for all future authorities for this provider. + p = new PackageParser.Provider(p); + p.syncable = false; + } + if (!mProvidersByAuthority.containsKey(names[j])) { + mProvidersByAuthority.put(names[j], p); + if (p.info.authority == null) { + p.info.authority = names[j]; + } else { + p.info.authority = p.info.authority + ";" + names[j]; + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + Log.d(TAG, "Registered content provider: " + names[j] + + ", className = " + p.info.name + + ", isSyncable = " + p.info.isSyncable); + } + } else { + final PackageParser.Provider other = + mProvidersByAuthority.get(names[j]); + final ComponentName component = + (other != null && other.getComponentName() != null) + ? other.getComponentName() : null; + final String packageName = + component != null ? component.getPackageName() : "?"; + Slog.w(TAG, "Skipping provider name " + names[j] + + " (in package " + pkg.applicationInfo.packageName + ")" + + ": name already used by " + packageName); + } + } + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(p.info.name); + } + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); + } + } + + @GuardedBy("mLock") + private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) { + final int receiversSize = pkg.receivers.size(); + StringBuilder r = null; + for (int i = 0; i < receiversSize; i++) { + PackageParser.Activity a = pkg.receivers.get(i); + a.info.processName = fixProcessName(pkg.applicationInfo.processName, + a.info.processName); + mReceivers.addActivity(a, "receiver", null); + if (DEBUG_PACKAGE_SCANNING && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(a.info.name); + } + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); + } + } + + @GuardedBy("mLock") + private void addServicesLocked(PackageParser.Package pkg, boolean chatty) { + final int servicesSize = pkg.services.size(); + StringBuilder r = null; + for (int i = 0; i < servicesSize; i++) { + PackageParser.Service s = pkg.services.get(i); + s.info.processName = fixProcessName(pkg.applicationInfo.processName, + s.info.processName); + mServices.addService(s); + if (DEBUG_PACKAGE_SCANNING && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(s.info.name); + } + } + if (DEBUG_PACKAGE_SCANNING && chatty) { + Log.d(TAG, " Services: " + (r == null ? "<NONE>" : r)); + } + } + + + /** + * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE + * MODIFIED. Do not pass in a list that should not be changed. + */ + private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList, + IterGenerator<T> generator, Iterator<T> searchIterator) { + // loop through the set of actions; every one must be found in the intent filter + while (searchIterator.hasNext()) { + // we must have at least one filter in the list to consider a match + if (intentList.size() == 0) { + break; + } + + final T searchAction = searchIterator.next(); + + // loop through the set of intent filters + final Iterator<ActivityIntentInfo> intentIter = intentList.iterator(); + while (intentIter.hasNext()) { + final ActivityIntentInfo intentInfo = intentIter.next(); + boolean selectionFound = false; + + // loop through the intent filter's selection criteria; at least one + // of them must match the searched criteria + final Iterator<T> intentSelectionIter = generator.generate(intentInfo); + while (intentSelectionIter != null && intentSelectionIter.hasNext()) { + final T intentSelection = intentSelectionIter.next(); + if (intentSelection != null && intentSelection.equals(searchAction)) { + selectionFound = true; + break; + } + } + + // the selection criteria wasn't found in this filter's set; this filter + // is not a potential match + if (!selectionFound) { + intentIter.remove(); + } + } + } + } + + private static boolean isProtectedAction(ActivityIntentInfo filter) { + final Iterator<String> actionsIter = filter.actionsIterator(); + while (actionsIter != null && actionsIter.hasNext()) { + final String filterAction = actionsIter.next(); + if (PROTECTED_ACTIONS.contains(filterAction)) { + return true; + } + } + return false; + } + + /** + * Finds a privileged activity that matches the specified activity names. + */ + private static PackageParser.Activity findMatchingActivity( + List<PackageParser.Activity> activityList, ActivityInfo activityInfo) { + for (PackageParser.Activity sysActivity : activityList) { + if (sysActivity.info.name.equals(activityInfo.name)) { + return sysActivity; + } + if (sysActivity.info.name.equals(activityInfo.targetActivity)) { + return sysActivity; + } + if (sysActivity.info.targetActivity != null) { + if (sysActivity.info.targetActivity.equals(activityInfo.name)) { + return sysActivity; + } + if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) { + return sysActivity; + } + } + } + return null; + } + + /** + * Adjusts the priority of the given intent filter according to policy. + * <p> + * <ul> + * <li>The priority for non privileged applications is capped to '0'</li> + * <li>The priority for protected actions on privileged applications is capped to '0'</li> + * <li>The priority for unbundled updates to privileged applications is capped to the + * priority defined on the system partition</li> + * </ul> + * <p> + * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is + * allowed to obtain any priority on any action. + */ + private void adjustPriority(List<PackageParser.Activity> systemActivities, + ActivityIntentInfo intent, String setupWizardPackage) { + // nothing to do; priority is fine as-is + if (intent.getPriority() <= 0) { + return; + } + + final ActivityInfo activityInfo = intent.activity.info; + final ApplicationInfo applicationInfo = activityInfo.applicationInfo; + + final boolean privilegedApp = + ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); + if (!privilegedApp) { + // non-privileged applications can never define a priority >0 + if (DEBUG_FILTERS) { + Slog.i(TAG, "Non-privileged app; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + + if (systemActivities == null) { + // the system package is not disabled; we're parsing the system partition + if (isProtectedAction(intent)) { + if (mDeferProtectedFilters) { + // We can't deal with these just yet. No component should ever obtain a + // >0 priority for a protected actions, with ONE exception -- the setup + // wizard. The setup wizard, however, cannot be known until we're able to + // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do + // until all intent filters have been processed. Chicken, meet egg. + // Let the filter temporarily have a high priority and rectify the + // priorities after all system packages have been scanned. + if (mProtectedFilters == null) { + mProtectedFilters = new ArrayList<>(); + } + mProtectedFilters.add(intent); + if (DEBUG_FILTERS) { + Slog.i(TAG, "Protected action; save for later;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + return; + } else { + if (DEBUG_FILTERS && setupWizardPackage == null) { + Slog.i(TAG, "No setup wizard;" + + " All protected intents capped to priority 0"); + } + if (intent.activity.info.packageName.equals(setupWizardPackage)) { + if (DEBUG_FILTERS) { + Slog.i(TAG, "Found setup wizard;" + + " allow priority " + intent.getPriority() + ";" + + " package: " + intent.activity.info.packageName + + " activity: " + intent.activity.className + + " priority: " + intent.getPriority()); + } + // setup wizard gets whatever it wants + return; + } + if (DEBUG_FILTERS) { + Slog.i(TAG, "Protected action; cap priority to 0;" + + " package: " + intent.activity.info.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + // privileged apps on the system image get whatever priority they request + return; + } + + // privileged app unbundled update ... try to find the same activity + final PackageParser.Activity foundActivity = + findMatchingActivity(systemActivities, activityInfo); + if (foundActivity == null) { + // this is a new activity; it cannot obtain >0 priority + if (DEBUG_FILTERS) { + Slog.i(TAG, "New activity; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + + // found activity, now check for filter equivalence + + // a shallow copy is enough; we modify the list, not its contents + final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents); + final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent); + + // find matching action subsets + final Iterator<String> actionsIterator = intent.actionsIterator(); + if (actionsIterator != null) { + getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched action; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching category subsets + final Iterator<String> categoriesIterator = intent.categoriesIterator(); + if (categoriesIterator != null) { + getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched category; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching schemes subsets + final Iterator<String> schemesIterator = intent.schemesIterator(); + if (schemesIterator != null) { + getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched scheme; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // find matching authorities subsets + final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator = + intent.authoritiesIterator(); + if (authoritiesIterator != null) { + getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(), + authoritiesIterator); + if (intentListCopy.size() == 0) { + // no more intents to match; we're not equivalent + if (DEBUG_FILTERS) { + Slog.i(TAG, "Mismatched authority; cap priority to 0;" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(0); + return; + } + } + + // we found matching filter(s); app gets the max priority of all intents + int cappedPriority = 0; + for (int i = intentListCopy.size() - 1; i >= 0; --i) { + cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority()); + } + if (intent.getPriority() > cappedPriority) { + if (DEBUG_FILTERS) { + Slog.i(TAG, "Found matching filter(s);" + + " cap priority to " + cappedPriority + ";" + + " package: " + applicationInfo.packageName + + " activity: " + intent.activity.className + + " origPrio: " + intent.getPriority()); + } + intent.setPriority(cappedPriority); + return; + } + // all this for nothing; the requested priority was <= what was on the system + } + + @GuardedBy("mLock") + private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) { + int componentSize; + StringBuilder r; + int i; + + componentSize = pkg.activities.size(); + r = null; + for (i = 0; i < componentSize; i++) { + PackageParser.Activity a = pkg.activities.get(i); + mActivities.removeActivity(a, "activity"); + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(a.info.name); + } + } + if (DEBUG_REMOVE && chatty) { + Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); + } + + componentSize = pkg.providers.size(); + r = null; + for (i = 0; i < componentSize; i++) { + PackageParser.Provider p = pkg.providers.get(i); + mProviders.removeProvider(p); + if (p.info.authority == null) { + // Another content provider with this authority existed when this app was + // installed, so this authority is null. Ignore it as we don't have to + // unregister the provider. + continue; + } + String[] names = p.info.authority.split(";"); + for (int j = 0; j < names.length; j++) { + if (mProvidersByAuthority.get(names[j]) == p) { + mProvidersByAuthority.remove(names[j]); + if (DEBUG_REMOVE && chatty) { + Log.d(TAG, "Unregistered content provider: " + names[j] + + ", className = " + p.info.name + ", isSyncable = " + + p.info.isSyncable); + } + } + } + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(p.info.name); + } + } + if (DEBUG_REMOVE && chatty) { + Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); + } + + componentSize = pkg.receivers.size(); + r = null; + for (i = 0; i < componentSize; i++) { + PackageParser.Activity a = pkg.receivers.get(i); + mReceivers.removeActivity(a, "receiver"); + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(a.info.name); + } + } + if (DEBUG_REMOVE && chatty) { + Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); + } + + componentSize = pkg.services.size(); + r = null; + for (i = 0; i < componentSize; i++) { + PackageParser.Service s = pkg.services.get(i); + mServices.removeService(s); + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(s.info.name); + } + } + if (DEBUG_REMOVE && chatty) { + Log.d(TAG, " Services: " + (r == null ? "<NONE>" : r)); + } + } + + @GuardedBy("mLock") + private void assertProvidersNotDefinedLocked(PackageParser.Package pkg) + throws PackageManagerException { + final int providersSize = pkg.providers.size(); + int i; + for (i = 0; i < providersSize; i++) { + PackageParser.Provider p = pkg.providers.get(i); + if (p.info.authority != null) { + final String[] names = p.info.authority.split(";"); + for (int j = 0; j < names.length; j++) { + if (mProvidersByAuthority.containsKey(names[j])) { + final PackageParser.Provider other = mProvidersByAuthority.get(names[j]); + final String otherPackageName = + (other != null && other.getComponentName() != null) + ? other.getComponentName().getPackageName() : "?"; + throw new PackageManagerException( + INSTALL_FAILED_CONFLICTING_PROVIDER, + "Can't install because provider name " + names[j] + + " (in package " + pkg.applicationInfo.packageName + + ") is already used by " + otherPackageName); + } + } + } + } + } + + private static final class ActivityIntentResolver + extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { + @Override + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, + boolean defaultOnly, int userId) { + if (!sUserManager.exists(userId)) return null; + mFlags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0); + return super.queryIntent(intent, resolvedType, defaultOnly, userId); + } + + List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, + int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + mFlags = flags; + return super.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId); + } + + List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, + int flags, List<PackageParser.Activity> packageActivities, int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + if (packageActivities == null) { + return null; + } + mFlags = flags; + final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; + final int activitiesSize = packageActivities.size(); + ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); + + ArrayList<PackageParser.ActivityIntentInfo> intentFilters; + for (int i = 0; i < activitiesSize; ++i) { + intentFilters = packageActivities.get(i).intents; + if (intentFilters != null && intentFilters.size() > 0) { + PackageParser.ActivityIntentInfo[] array = + new PackageParser.ActivityIntentInfo[intentFilters.size()]; + intentFilters.toArray(array); + listCut.add(array); + } + } + return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); + } + + private void addActivity(PackageParser.Activity a, String type, + List<PackageParser.ActivityIntentInfo> newIntents) { + mActivities.put(a.getComponentName(), a); + if (DEBUG_SHOW_INFO) { + final CharSequence label = a.info.nonLocalizedLabel != null + ? a.info.nonLocalizedLabel + : a.info.name; + Log.v(TAG, " " + type + " " + label + ":"); + } + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " Class=" + a.info.name); + } + final int intentsSize = a.intents.size(); + for (int j = 0; j < intentsSize; j++) { + PackageParser.ActivityIntentInfo intent = a.intents.get(j); + if (newIntents != null && "activity".equals(type)) { + newIntents.add(intent); + } + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + if (!intent.debugCheck()) { + Log.w(TAG, "==> For Activity " + a.info.name); + } + addFilter(intent); + } + } + + private void removeActivity(PackageParser.Activity a, String type) { + mActivities.remove(a.getComponentName()); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + type + " " + + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel + : a.info.name) + ":"); + Log.v(TAG, " Class=" + a.info.name); + } + final int intentsSize = a.intents.size(); + for (int j = 0; j < intentsSize; j++) { + PackageParser.ActivityIntentInfo intent = a.intents.get(j); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + removeFilter(intent); + } + } + + @Override + protected boolean allowFilterResult( + PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) { + ActivityInfo filterAi = filter.activity.info; + for (int i = dest.size() - 1; i >= 0; --i) { + ActivityInfo destAi = dest.get(i).activityInfo; + if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) { + return false; + } + } + return true; + } + + @Override + protected ActivityIntentInfo[] newArray(int size) { + return new ActivityIntentInfo[size]; + } + + @Override + protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; + PackageParser.Package p = filter.activity.owner; + if (p != null) { + PackageSetting ps = (PackageSetting) p.mExtras; + if (ps != null) { + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); + } + } + return false; + } + + @Override + protected boolean isPackageForFilter(String packageName, + PackageParser.ActivityIntentInfo info) { + return packageName.equals(info.activity.owner.packageName); + } + + @Override + protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, + int match, int userId) { + if (!sUserManager.exists(userId)) return null; + if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) { + return null; + } + final PackageParser.Activity activity = info.activity; + PackageSetting ps = (PackageSetting) activity.owner.mExtras; + if (ps == null) { + return null; + } + final PackageUserState userState = ps.readUserState(userId); + ActivityInfo ai = + PackageParser.generateActivityInfo(activity, mFlags, userState, userId); + if (ai == null) { + return null; + } + final boolean matchExplicitlyVisibleOnly = + (mFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; + final boolean matchVisibleToInstantApp = + (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; + final boolean componentVisible = + matchVisibleToInstantApp + && info.isVisibleToInstantApp() + && (!matchExplicitlyVisibleOnly || info.isExplicitlyVisibleToInstantApp()); + final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; + // throw out filters that aren't visible to ephemeral apps + if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) { + return null; + } + // throw out instant app filters if we're not explicitly requesting them + if (!matchInstantApp && userState.instantApp) { + return null; + } + // throw out instant app filters if updates are available; will trigger + // instant app resolution + if (userState.instantApp && ps.isUpdateAvailable()) { + return null; + } + final ResolveInfo res = new ResolveInfo(); + res.activityInfo = ai; + if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { + res.filter = info; + } + res.handleAllWebDataURI = info.handleAllWebDataURI(); + res.priority = info.getPriority(); + res.preferredOrder = activity.owner.mPreferredOrder; + //System.out.println("Result: " + res.activityInfo.className + + // " = " + res.priority); + res.match = match; + res.isDefault = info.hasDefault; + res.labelRes = info.labelRes; + res.nonLocalizedLabel = info.nonLocalizedLabel; + if (sPackageManagerInternal.userNeedsBadging(userId)) { + res.noResourceId = true; + } else { + res.icon = info.icon; + } + res.iconResourceId = info.icon; + res.system = res.activityInfo.applicationInfo.isSystemApp(); + res.isInstantAppAvailable = userState.instantApp; + return res; + } + + @Override + protected void sortResults(List<ResolveInfo> results) { + results.sort(RESOLVE_PRIORITY_SORTER); + } + + @Override + protected void dumpFilter(PrintWriter out, String prefix, + PackageParser.ActivityIntentInfo filter) { + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(filter.activity))); + out.print(' '); + filter.activity.printComponentShortName(out); + out.print(" filter "); + out.println(Integer.toHexString(System.identityHashCode(filter))); + } + + @Override + protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) { + return filter.activity; + } + + protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { + PackageParser.Activity activity = (PackageParser.Activity) label; + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(activity))); + out.print(' '); + activity.printComponentShortName(out); + if (count > 1) { + out.print(" ("); out.print(count); out.print(" filters)"); + } + out.println(); + } + + // Keys are String (activity class name), values are Activity. + private final ArrayMap<ComponentName, PackageParser.Activity> mActivities = + new ArrayMap<>(); + private int mFlags; + } + + private static final class ProviderIntentResolver + extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> { + @Override + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, + boolean defaultOnly, int userId) { + mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; + return super.queryIntent(intent, resolvedType, defaultOnly, userId); + } + + List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, + int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + mFlags = flags; + return super.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId); + } + + List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, + int flags, List<PackageParser.Provider> packageProviders, int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + if (packageProviders == null) { + return null; + } + mFlags = flags; + final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; + final int providersSize = packageProviders.size(); + ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); + + ArrayList<PackageParser.ProviderIntentInfo> intentFilters; + for (int i = 0; i < providersSize; ++i) { + intentFilters = packageProviders.get(i).intents; + if (intentFilters != null && intentFilters.size() > 0) { + PackageParser.ProviderIntentInfo[] array = + new PackageParser.ProviderIntentInfo[intentFilters.size()]; + intentFilters.toArray(array); + listCut.add(array); + } + } + return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); + } + + void addProvider(PackageParser.Provider p) { + if (mProviders.containsKey(p.getComponentName())) { + Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring"); + return; + } + + mProviders.put(p.getComponentName(), p); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + + (p.info.nonLocalizedLabel != null + ? p.info.nonLocalizedLabel + : p.info.name) + + ":"); + Log.v(TAG, " Class=" + p.info.name); + } + final int intentsSize = p.intents.size(); + int j; + for (j = 0; j < intentsSize; j++) { + PackageParser.ProviderIntentInfo intent = p.intents.get(j); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + if (!intent.debugCheck()) { + Log.w(TAG, "==> For Provider " + p.info.name); + } + addFilter(intent); + } + } + + void removeProvider(PackageParser.Provider p) { + mProviders.remove(p.getComponentName()); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + (p.info.nonLocalizedLabel != null + ? p.info.nonLocalizedLabel + : p.info.name) + ":"); + Log.v(TAG, " Class=" + p.info.name); + } + final int intentsSize = p.intents.size(); + int j; + for (j = 0; j < intentsSize; j++) { + PackageParser.ProviderIntentInfo intent = p.intents.get(j); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + removeFilter(intent); + } + } + + @Override + protected boolean allowFilterResult( + PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) { + ProviderInfo filterPi = filter.provider.info; + for (int i = dest.size() - 1; i >= 0; i--) { + ProviderInfo destPi = dest.get(i).providerInfo; + if (destPi.name == filterPi.name + && destPi.packageName == filterPi.packageName) { + return false; + } + } + return true; + } + + @Override + protected PackageParser.ProviderIntentInfo[] newArray(int size) { + return new PackageParser.ProviderIntentInfo[size]; + } + + @Override + protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) { + return true; + } + PackageParser.Package p = filter.provider.owner; + if (p != null) { + PackageSetting ps = (PackageSetting) p.mExtras; + if (ps != null) { + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); + } + } + return false; + } + + @Override + protected boolean isPackageForFilter(String packageName, + PackageParser.ProviderIntentInfo info) { + return packageName.equals(info.provider.owner.packageName); + } + + @Override + protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter, + int match, int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + final PackageParser.ProviderIntentInfo info = filter; + if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) { + return null; + } + final PackageParser.Provider provider = info.provider; + PackageSetting ps = (PackageSetting) provider.owner.mExtras; + if (ps == null) { + return null; + } + final PackageUserState userState = ps.readUserState(userId); + final boolean matchVisibleToInstantApp = (mFlags + & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; + final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; + // throw out filters that aren't visible to instant applications + if (matchVisibleToInstantApp + && !(info.isVisibleToInstantApp() || userState.instantApp)) { + return null; + } + // throw out instant application filters if we're not explicitly requesting them + if (!isInstantApp && userState.instantApp) { + return null; + } + // throw out instant application filters if updates are available; will trigger + // instant application resolution + if (userState.instantApp && ps.isUpdateAvailable()) { + return null; + } + ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags, + userState, userId); + if (pi == null) { + return null; + } + final ResolveInfo res = new ResolveInfo(); + res.providerInfo = pi; + if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { + res.filter = filter; + } + res.priority = info.getPriority(); + res.preferredOrder = provider.owner.mPreferredOrder; + res.match = match; + res.isDefault = info.hasDefault; + res.labelRes = info.labelRes; + res.nonLocalizedLabel = info.nonLocalizedLabel; + res.icon = info.icon; + res.system = res.providerInfo.applicationInfo.isSystemApp(); + return res; + } + + @Override + protected void sortResults(List<ResolveInfo> results) { + results.sort(RESOLVE_PRIORITY_SORTER); + } + + @Override + protected void dumpFilter(PrintWriter out, String prefix, + PackageParser.ProviderIntentInfo filter) { + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(filter.provider))); + out.print(' '); + filter.provider.printComponentShortName(out); + out.print(" filter "); + out.println(Integer.toHexString(System.identityHashCode(filter))); + } + + @Override + protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) { + return filter.provider; + } + + protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { + final PackageParser.Provider provider = (PackageParser.Provider) label; + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(provider))); + out.print(' '); + provider.printComponentShortName(out); + if (count > 1) { + out.print(" ("); + out.print(count); + out.print(" filters)"); + } + out.println(); + } + + private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>(); + private int mFlags; + } + + private static final class ServiceIntentResolver + extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { + @Override + public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, + boolean defaultOnly, int userId) { + mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; + return super.queryIntent(intent, resolvedType, defaultOnly, userId); + } + + List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, + int userId) { + if (!sUserManager.exists(userId)) return null; + mFlags = flags; + return super.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId); + } + + List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, + int flags, List<PackageParser.Service> packageServices, int userId) { + if (!sUserManager.exists(userId)) return null; + if (packageServices == null) { + return null; + } + mFlags = flags; + final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; + final int servicesSize = packageServices.size(); + ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); + + ArrayList<PackageParser.ServiceIntentInfo> intentFilters; + for (int i = 0; i < servicesSize; ++i) { + intentFilters = packageServices.get(i).intents; + if (intentFilters != null && intentFilters.size() > 0) { + PackageParser.ServiceIntentInfo[] array = + new PackageParser.ServiceIntentInfo[intentFilters.size()]; + intentFilters.toArray(array); + listCut.add(array); + } + } + return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); + } + + void addService(PackageParser.Service s) { + mServices.put(s.getComponentName(), s); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + + (s.info.nonLocalizedLabel != null + ? s.info.nonLocalizedLabel : s.info.name) + ":"); + Log.v(TAG, " Class=" + s.info.name); + } + final int intentsSize = s.intents.size(); + int j; + for (j = 0; j < intentsSize; j++) { + PackageParser.ServiceIntentInfo intent = s.intents.get(j); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + if (!intent.debugCheck()) { + Log.w(TAG, "==> For Service " + s.info.name); + } + addFilter(intent); + } + } + + void removeService(PackageParser.Service s) { + mServices.remove(s.getComponentName()); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " " + (s.info.nonLocalizedLabel != null + ? s.info.nonLocalizedLabel : s.info.name) + ":"); + Log.v(TAG, " Class=" + s.info.name); + } + final int intentsSize = s.intents.size(); + int j; + for (j = 0; j < intentsSize; j++) { + PackageParser.ServiceIntentInfo intent = s.intents.get(j); + if (DEBUG_SHOW_INFO) { + Log.v(TAG, " IntentFilter:"); + intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); + } + removeFilter(intent); + } + } + + @Override + protected boolean allowFilterResult( + PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) { + ServiceInfo filterSi = filter.service.info; + for (int i = dest.size() - 1; i >= 0; --i) { + ServiceInfo destAi = dest.get(i).serviceInfo; + if (destAi.name == filterSi.name + && destAi.packageName == filterSi.packageName) { + return false; + } + } + return true; + } + + @Override + protected PackageParser.ServiceIntentInfo[] newArray(int size) { + return new PackageParser.ServiceIntentInfo[size]; + } + + @Override + protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; + PackageParser.Package p = filter.service.owner; + if (p != null) { + PackageSetting ps = (PackageSetting) p.mExtras; + if (ps != null) { + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); + } + } + return false; + } + + @Override + protected boolean isPackageForFilter(String packageName, + PackageParser.ServiceIntentInfo info) { + return packageName.equals(info.service.owner.packageName); + } + + @Override + protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, + int match, int userId) { + if (!sUserManager.exists(userId)) return null; + final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter; + if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) { + return null; + } + final PackageParser.Service service = info.service; + PackageSetting ps = (PackageSetting) service.owner.mExtras; + if (ps == null) { + return null; + } + final PackageUserState userState = ps.readUserState(userId); + ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags, + userState, userId); + if (si == null) { + return null; + } + final boolean matchVisibleToInstantApp = + (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; + final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; + // throw out filters that aren't visible to ephemeral apps + if (matchVisibleToInstantApp + && !(info.isVisibleToInstantApp() || userState.instantApp)) { + return null; + } + // throw out ephemeral filters if we're not explicitly requesting them + if (!isInstantApp && userState.instantApp) { + return null; + } + // throw out instant app filters if updates are available; will trigger + // instant app resolution + if (userState.instantApp && ps.isUpdateAvailable()) { + return null; + } + final ResolveInfo res = new ResolveInfo(); + res.serviceInfo = si; + if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { + res.filter = filter; + } + res.priority = info.getPriority(); + res.preferredOrder = service.owner.mPreferredOrder; + res.match = match; + res.isDefault = info.hasDefault; + res.labelRes = info.labelRes; + res.nonLocalizedLabel = info.nonLocalizedLabel; + res.icon = info.icon; + res.system = res.serviceInfo.applicationInfo.isSystemApp(); + return res; + } + + @Override + protected void sortResults(List<ResolveInfo> results) { + results.sort(RESOLVE_PRIORITY_SORTER); + } + + @Override + protected void dumpFilter(PrintWriter out, String prefix, + PackageParser.ServiceIntentInfo filter) { + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(filter.service))); + out.print(' '); + filter.service.printComponentShortName(out); + out.print(" filter "); + out.print(Integer.toHexString(System.identityHashCode(filter))); + if (filter.service.info.permission != null) { + out.print(" permission "); out.println(filter.service.info.permission); + } else { + out.println(); + } + } + + @Override + protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) { + return filter.service; + } + + protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { + final PackageParser.Service service = (PackageParser.Service) label; + out.print(prefix); + out.print(Integer.toHexString(System.identityHashCode(service))); + out.print(' '); + service.printComponentShortName(out); + if (count > 1) { + out.print(" ("); out.print(count); out.print(" filters)"); + } + out.println(); + } + + // Keys are String (activity class name), values are Activity. + private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>(); + private int mFlags; + } + + static final class InstantAppIntentResolver + extends IntentResolver<AuxiliaryResolveInfo.AuxiliaryFilter, + AuxiliaryResolveInfo.AuxiliaryFilter> { + /** + * The result that has the highest defined order. Ordering applies on a + * per-package basis. Mapping is from package name to Pair of order and + * EphemeralResolveInfo. + * <p> + * NOTE: This is implemented as a field variable for convenience and efficiency. + * By having a field variable, we're able to track filter ordering as soon as + * a non-zero order is defined. Otherwise, multiple loops across the result set + * would be needed to apply ordering. If the intent resolver becomes re-entrant, + * this needs to be contained entirely within {@link #filterResults}. + */ + final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = + new ArrayMap<>(); + + @Override + protected AuxiliaryResolveInfo.AuxiliaryFilter[] newArray(int size) { + return new AuxiliaryResolveInfo.AuxiliaryFilter[size]; + } + + @Override + protected boolean isPackageForFilter(String packageName, + AuxiliaryResolveInfo.AuxiliaryFilter responseObj) { + return true; + } + + @Override + protected AuxiliaryResolveInfo.AuxiliaryFilter newResult( + AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId) { + if (!sUserManager.exists(userId)) { + return null; + } + final String packageName = responseObj.resolveInfo.getPackageName(); + final Integer order = responseObj.getOrder(); + final Pair<Integer, InstantAppResolveInfo> lastOrderResult = + mOrderResult.get(packageName); + // ordering is enabled and this item's order isn't high enough + if (lastOrderResult != null && lastOrderResult.first >= order) { + return null; + } + final InstantAppResolveInfo res = responseObj.resolveInfo; + if (order > 0) { + // non-zero order, enable ordering + mOrderResult.put(packageName, new Pair<>(order, res)); + } + return responseObj; + } + + @Override + protected void filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results) { + // only do work if ordering is enabled [most of the time it won't be] + if (mOrderResult.size() == 0) { + return; + } + int resultSize = results.size(); + for (int i = 0; i < resultSize; i++) { + final InstantAppResolveInfo info = results.get(i).resolveInfo; + final String packageName = info.getPackageName(); + final Pair<Integer, InstantAppResolveInfo> savedInfo = + mOrderResult.get(packageName); + if (savedInfo == null) { + // package doesn't having ordering + continue; + } + if (savedInfo.second == info) { + // circled back to the highest ordered item; remove from order list + mOrderResult.remove(packageName); + if (mOrderResult.size() == 0) { + // no more ordered items + break; + } + continue; + } + // item has a worse order, remove it from the result list + results.remove(i); + resultSize--; + i--; + } + } + } + + /** Generic to create an {@link Iterator} for a data type */ + static class IterGenerator<E> { + public Iterator<E> generate(ActivityIntentInfo info) { + return null; + } + } + + /** Create an {@link Iterator} for intent actions */ + static class ActionIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.actionsIterator(); + } + } + + /** Create an {@link Iterator} for intent categories */ + static class CategoriesIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.categoriesIterator(); + } + } + + /** Create an {@link Iterator} for intent schemes */ + static class SchemesIterGenerator extends IterGenerator<String> { + @Override + public Iterator<String> generate(ActivityIntentInfo info) { + return info.schemesIterator(); + } + } + + /** Create an {@link Iterator} for intent authorities */ + static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { + @Override + public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) { + return info.authoritiesIterator(); + } + } + +} diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java index 19cefb8a6ceb..9bd3924b9866 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolver.java +++ b/services/core/java/com/android/server/pm/InstantAppResolver.java @@ -36,9 +36,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ActivityInfo; -import android.content.pm.InstantAppRequest; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.InstantAppIntentFilter; +import android.content.pm.InstantAppRequest; import android.content.pm.InstantAppResolveInfo; import android.content.pm.InstantAppResolveInfo.InstantAppDigest; import android.metrics.LogMaker; @@ -458,8 +458,8 @@ public abstract class InstantAppResolver { } return Collections.emptyList(); } - final PackageManagerService.InstantAppIntentResolver instantAppResolver = - new PackageManagerService.InstantAppIntentResolver(); + final ComponentResolver.InstantAppIntentResolver instantAppResolver = + new ComponentResolver.InstantAppIntentResolver(); for (int j = instantAppFilters.size() - 1; j >= 0; --j) { final InstantAppIntentFilter instantAppFilter = instantAppFilters.get(j); final List<IntentFilter> splitFilters = instantAppFilter.getFilters(); diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 320affb1eee2..cf47d4e6af87 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -365,10 +365,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub { continue; } - // If the path is in /system, /vendor or /product, ignore. It will have been - // ota-dexopted into /data/ota and moved into the dalvik-cache already. - if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor") - || pkg.codePath.startsWith("/product")) { + // If the path is in /system, /vendor, /product or /product_services, ignore. It will + // have been ota-dexopted into /data/ota and moved into the dalvik-cache already. + if (pkg.codePath.startsWith("/system") + || pkg.codePath.startsWith("/vendor") + || pkg.codePath.startsWith("/product") + || pkg.codePath.startsWith("/product_services")) { continue; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f3d333b751c0..29255230eeb9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -24,6 +24,7 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.REQUEST_DELETE_PACKAGES; import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_DEFAULT; import static android.content.Intent.CATEGORY_HOME; @@ -44,7 +45,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.INSTALL_EXTERNAL; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; -import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; import static android.content.pm.PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID; @@ -95,6 +95,7 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT; import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; +import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; @@ -158,7 +159,6 @@ import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstantAppInfo; import android.content.pm.InstantAppRequest; -import android.content.pm.InstantAppResolveInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; @@ -177,7 +177,6 @@ import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; -import android.content.pm.PackageParser.ServiceIntentInfo; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.PackageStats; @@ -254,6 +253,7 @@ import android.util.ByteStringUtils; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.ExceptionUtils; +import android.util.IntArray; import android.util.Log; import android.util.LogPrinter; import android.util.LongSparseArray; @@ -294,7 +294,6 @@ import com.android.server.AttributeCache; import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; import com.android.server.FgThread; -import com.android.server.IntentResolver; import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.ServiceThread; @@ -415,12 +414,10 @@ public class PackageManagerService extends IPackageManager.Stub public static final boolean DEBUG_INSTALL = false; public static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; - private static final boolean DEBUG_SHOW_INFO = false; private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; public static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_VERIFY = false; - private static final boolean DEBUG_FILTERS = false; public static final boolean DEBUG_PERMISSIONS = false; private static final boolean DEBUG_SHARED_LIBRARIES = false; public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE; @@ -449,26 +446,27 @@ public class PackageManagerService extends IPackageManager.Stub private static final int SHELL_UID = Process.SHELL_UID; private static final int SE_UID = Process.SE_UID; - static final int SCAN_NO_DEX = 1<<0; - static final int SCAN_UPDATE_SIGNATURE = 1<<1; - static final int SCAN_NEW_INSTALL = 1<<2; - static final int SCAN_UPDATE_TIME = 1<<3; - static final int SCAN_BOOTING = 1<<4; - static final int SCAN_REQUIRE_KNOWN = 1<<7; - static final int SCAN_MOVE = 1<<8; - static final int SCAN_INITIAL = 1<<9; - static final int SCAN_CHECK_ONLY = 1<<10; - static final int SCAN_DONT_KILL_APP = 1<<11; - static final int SCAN_IGNORE_FROZEN = 1<<12; - static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<13; - static final int SCAN_AS_INSTANT_APP = 1<<14; - static final int SCAN_AS_FULL_APP = 1<<15; - static final int SCAN_AS_VIRTUAL_PRELOAD = 1<<16; - static final int SCAN_AS_SYSTEM = 1<<17; - static final int SCAN_AS_PRIVILEGED = 1<<18; - static final int SCAN_AS_OEM = 1<<19; - static final int SCAN_AS_VENDOR = 1<<20; - static final int SCAN_AS_PRODUCT = 1<<21; + static final int SCAN_NO_DEX = 1 << 0; + static final int SCAN_UPDATE_SIGNATURE = 1 << 1; + static final int SCAN_NEW_INSTALL = 1 << 2; + static final int SCAN_UPDATE_TIME = 1 << 3; + static final int SCAN_BOOTING = 1 << 4; + static final int SCAN_REQUIRE_KNOWN = 1 << 7; + static final int SCAN_MOVE = 1 << 8; + static final int SCAN_INITIAL = 1 << 9; + static final int SCAN_CHECK_ONLY = 1 << 10; + static final int SCAN_DONT_KILL_APP = 1 << 11; + static final int SCAN_IGNORE_FROZEN = 1 << 12; + static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13; + static final int SCAN_AS_INSTANT_APP = 1 << 14; + static final int SCAN_AS_FULL_APP = 1 << 15; + static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16; + static final int SCAN_AS_SYSTEM = 1 << 17; + static final int SCAN_AS_PRIVILEGED = 1 << 18; + static final int SCAN_AS_OEM = 1 << 19; + static final int SCAN_AS_VENDOR = 1 << 20; + static final int SCAN_AS_PRODUCT = 1 << 21; + static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -574,6 +572,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String PRODUCT_OVERLAY_DIR = "/product/overlay"; + private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; + /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -584,18 +584,6 @@ public class PackageManagerService extends IPackageManager.Stub sBrowserIntent.addFlags(Intent.FLAG_IGNORE_EPHEMERAL); } - /** - * The set of all protected actions [i.e. those actions for which a high priority - * intent filter is disallowed]. - */ - private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>(); - static { - PROTECTED_ACTIONS.add(Intent.ACTION_SEND); - PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO); - PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE); - PROTECTED_ACTIONS.add(Intent.ACTION_VIEW); - } - // Compilation reasons. public static final int REASON_UNKNOWN = -1; public static final int REASON_FIRST_BOOT = 0; @@ -697,20 +685,6 @@ public class PackageManagerService extends IPackageManager.Stub * are package location. */ final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>(); - /** - * Tracks high priority intent filters for protected actions. During boot, certain - * filter actions are protected and should never be allowed to have a high priority - * intent filter for them. However, there is one, and only one exception -- the - * setup wizard. It must be able to define a high priority intent filter for these - * actions to ensure there are no escapes from the wizard. We need to delay processing - * of these during boot as we need to look at all of the system packages in order - * to know which component is the setup wizard. - */ - private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>(); - /** - * Whether or not processing protected filters should be deferred. - */ - private boolean mDeferProtectedFilters = true; /** * Tracks existing system packages prior to receiving an OTA. Keys are package name. @@ -908,24 +882,6 @@ public class PackageManagerService extends IPackageManager.Stub final ArrayMap<String, LongSparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage = new ArrayMap<>(); - // All available activities, for your resolving pleasure. - final ActivityIntentResolver mActivities = - new ActivityIntentResolver(); - - // All available receivers, for your resolving pleasure. - final ActivityIntentResolver mReceivers = - new ActivityIntentResolver(); - - // All available services, for your resolving pleasure. - final ServiceIntentResolver mServices = new ServiceIntentResolver(); - - // All available providers, for your resolving pleasure. - final ProviderIntentResolver mProviders = new ProviderIntentResolver(); - - // Mapping from provider base names (first directory in content URI codePath) - // to the provider information. - final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>(); - // Mapping from instrumentation class names to info about them. final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = new ArrayMap<>(); @@ -956,7 +912,7 @@ public class PackageManagerService extends IPackageManager.Stub private final OnPermissionChangeListeners mOnPermissionChangeListeners; // Cache of users who need badging. - SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); + private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; @@ -996,6 +952,7 @@ public class PackageManagerService extends IPackageManager.Stub final DefaultPermissionGrantPolicy mDefaultPermissionPolicy; private final PermissionManagerInternal mPermissionManager; + private final ComponentResolver mComponentResolver; // List of packages names to keep cached, even if they are uninstalled for all users private List<String> mKeepUninstalledPackages; @@ -2411,6 +2368,9 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerInternal.class, new PackageManagerInternalImpl()); sUserManager = new UserManagerService(context, this, new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages); + mComponentResolver = new ComponentResolver(sUserManager, + LocalServices.getService(PackageManagerInternal.class), + mPackages); mPermissionManager = PermissionManagerService.create(context, new DefaultPermissionGrantedCallback() { @Override @@ -2421,7 +2381,8 @@ public class PackageManagerService extends IPackageManager.Stub } }, mPackages /*externalLock*/); mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy(); - mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages); + mSettings = new Settings(Environment.getDataDirectory(), + mPermissionManager.getPermissionSettings(), mPackages); } } mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, @@ -2589,9 +2550,10 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } - // Collect vendor/product overlay packages. (Do this before scanning any apps.) - // For security and version matching reason, only consider - // overlay packages if they reside in the right directory. + // Collect vendor/product/product_services overlay packages. (Do this before scanning + // any apps.) + // For security and version matching reason, only consider overlay packages if they + // reside in the right directory. scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, @@ -2606,6 +2568,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT, 0); + scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT_SERVICES, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); @@ -2717,7 +2686,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_OEM, 0); - // Collected privileged product packages. + // Collected privileged /product packages. File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); try { privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile(); @@ -2733,7 +2702,7 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_PRIVILEGED, 0); - // Collect ordinary product packages. + // Collect ordinary /product packages. File productAppDir = new File(Environment.getProductDirectory(), "app"); try { productAppDir = productAppDir.getCanonicalFile(); @@ -2748,6 +2717,39 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_PRODUCT, 0); + // Collected privileged /product_services packages. + File privilegedProductServicesAppDir = + new File(Environment.getProductServicesDirectory(), "priv-app"); + try { + privilegedProductServicesAppDir = + privilegedProductServicesAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(privilegedProductServicesAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT_SERVICES + | SCAN_AS_PRIVILEGED, + 0); + + // Collect ordinary /product_services packages. + File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app"); + try { + productServicesAppDir = productServicesAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(productServicesAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT_SERVICES, + 0); + // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); // Stub packages must either be replaced with full versions in the /data @@ -2952,6 +2954,23 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT; + } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT_SERVICES + | SCAN_AS_PRIVILEGED; + } else if (FileUtils.contains(productServicesAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT_SERVICES; } else { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; @@ -2995,38 +3014,10 @@ public class PackageManagerService extends IPackageManager.Stub // Resolve protected action filters. Only the setup wizard is allowed to // have a high priority filter for these actions. mSetupWizardPackage = getSetupWizardPackageName(); - if (mProtectedFilters.size() > 0) { - if (DEBUG_FILTERS && mSetupWizardPackage == null) { - Slog.i(TAG, "No setup wizard;" - + " All protected intents capped to priority 0"); - } - for (ActivityIntentInfo filter : mProtectedFilters) { - if (filter.activity.info.packageName.equals(mSetupWizardPackage)) { - if (DEBUG_FILTERS) { - Slog.i(TAG, "Found setup wizard;" - + " allow priority " + filter.getPriority() + ";" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className - + " priority: " + filter.getPriority()); - } - // skip setup wizard; allow it to keep the high priority filter - continue; - } - if (DEBUG_FILTERS) { - Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className - + " origPrio: " + filter.getPriority()); - } - filter.setPriority(0); - } - } + mComponentResolver.fixProtectedFilterPriorities(); mSystemTextClassifierPackage = getSystemTextClassifierPackageName(); - mDeferProtectedFilters = false; - mProtectedFilters.clear(); - // Now that we know all of the shared libraries, update all clients to have // the correct library paths. updateAllSharedLibrariesLPw(null); @@ -3084,7 +3075,7 @@ public class PackageManagerService extends IPackageManager.Stub // all defined users. if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) { for (UserInfo user : sUserManager.getUsers(true)) { - mSettings.applyDefaultPreferredAppsLPw(this, user.id); + mSettings.applyDefaultPreferredAppsLPw(user.id); applyFactoryDefaultBrowserLPw(user.id); primeDomainVerificationsLPw(user.id); } @@ -4180,7 +4171,7 @@ public class PackageManagerService extends IPackageManager.Stub private boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { - final PackageParser.Activity activity = mActivities.mActivities.get(component); + final PackageParser.Activity activity = mComponentResolver.getActivity(component); if (activity == null) { return false; } @@ -4190,7 +4181,7 @@ public class PackageManagerService extends IPackageManager.Stub (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { - final PackageParser.Activity activity = mReceivers.mActivities.get(component); + final PackageParser.Activity activity = mComponentResolver.getReceiver(component); if (activity == null) { return false; } @@ -4200,12 +4191,12 @@ public class PackageManagerService extends IPackageManager.Stub (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { - final PackageParser.Service service = mServices.mServices.get(component); + final PackageParser.Service service = mComponentResolver.getService(component); return service != null ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; } else if (type == TYPE_PROVIDER) { - final PackageParser.Provider provider = mProviders.mProviders.get(component); + final PackageParser.Provider provider = mComponentResolver.getProvider(component); return provider != null ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; @@ -4953,7 +4944,7 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mPackages) { - PackageParser.Activity a = mActivities.mActivities.get(component); + PackageParser.Activity a = mComponentResolver.getActivity(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { @@ -4999,7 +4990,7 @@ public class PackageManagerService extends IPackageManager.Stub } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - PackageParser.Activity a = mActivities.mActivities.get(component); + PackageParser.Activity a = mComponentResolver.getActivity(component); if (a == null) { return false; } @@ -5028,7 +5019,7 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get receiver info"); synchronized (mPackages) { - PackageParser.Activity a = mReceivers.mActivities.get(component); + PackageParser.Activity a = mComponentResolver.getReceiver(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { @@ -5166,7 +5157,7 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get service info"); synchronized (mPackages) { - PackageParser.Service s = mServices.mServices.get(component); + PackageParser.Service s = mComponentResolver.getService(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) { @@ -5190,7 +5181,7 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get provider info"); synchronized (mPackages) { - PackageParser.Provider p = mProviders.mProviders.get(component); + PackageParser.Provider p = mComponentResolver.getProvider(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) { @@ -6744,7 +6735,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Check for results in the current profile. - result = filterIfNotSystemUser(mActivities.queryIntent( + result = filterIfNotSystemUser(mComponentResolver.queryActivities( intent, resolvedType, flags, userId), userId); addInstant = isInstantAppResolutionAllowed(intent, result, userId, false /*skipPackageCheck*/); @@ -6801,10 +6792,8 @@ public class PackageManagerService extends IPackageManager.Stub final PackageParser.Package pkg = mPackages.get(pkgName); result = null; if (pkg != null) { - result = filterIfNotSystemUser( - mActivities.queryIntentForPackage( - intent, resolvedType, flags, pkg.activities, userId), - userId); + result = filterIfNotSystemUser(mComponentResolver.queryActivities( + intent, resolvedType, flags, pkg.activities, userId), userId); } if (result == null || result.size() == 0) { // the caller wants to resolve for a particular package; however, there @@ -6822,7 +6811,7 @@ public class PackageManagerService extends IPackageManager.Stub result, intent, resolvedType, flags, userId, resolveForStart); } if (sortResult) { - Collections.sort(result, mResolvePrioritySorter); + Collections.sort(result, RESOLVE_PRIORITY_SORTER); } return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, @@ -6836,7 +6825,9 @@ public class PackageManagerService extends IPackageManager.Stub ResolveInfo localInstantApp = null; boolean blockResolution = false; if (!alreadyResolvedLocally) { - final List<ResolveInfo> instantApps = mActivities.queryIntent(intent, resolvedType, + final List<ResolveInfo> instantApps = mComponentResolver.queryActivities( + intent, + resolvedType, flags | PackageManager.GET_RESOLVED_FILTER | PackageManager.MATCH_INSTANT @@ -6942,7 +6933,7 @@ public class PackageManagerService extends IPackageManager.Stub sourceUserId)) { return null; } - List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent, + List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent, resolvedType, flags, parentUserId); if (resultTargetUser == null || resultTargetUser.isEmpty()) { @@ -7382,7 +7373,7 @@ public class PackageManagerService extends IPackageManager.Stub private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent, String resolvedType, int flags, int sourceUserId) { int targetUserId = filter.getTargetUserId(); - List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent, + List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent, resolvedType, flags, targetUserId); if (resultTargetUser != null && isUserEnabled(targetUserId)) { // If all the matches in the target profile are suspended, return null. @@ -7690,14 +7681,14 @@ public class PackageManagerService extends IPackageManager.Stub String pkgName = intent.getPackage(); if (pkgName == null) { final List<ResolveInfo> result = - mReceivers.queryIntent(intent, resolvedType, flags, userId); + mComponentResolver.queryReceivers(intent, resolvedType, flags, userId); return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - final List<ResolveInfo> result = mReceivers.queryIntentForPackage( + final List<ResolveInfo> result = mComponentResolver.queryReceivers( intent, resolvedType, flags, pkg.receivers, userId); return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, @@ -7794,13 +7785,13 @@ public class PackageManagerService extends IPackageManager.Stub String pkgName = intent.getPackage(); if (pkgName == null) { return applyPostServiceResolutionFilter( - mServices.queryIntent(intent, resolvedType, flags, userId), + mComponentResolver.queryServices(intent, resolvedType, flags, userId), instantAppPkgName); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return applyPostServiceResolutionFilter( - mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services, + mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services, userId), instantAppPkgName); } @@ -7912,14 +7903,14 @@ public class PackageManagerService extends IPackageManager.Stub String pkgName = intent.getPackage(); if (pkgName == null) { return applyPostContentProviderResolutionFilter( - mProviders.queryIntent(intent, resolvedType, flags, userId), + mComponentResolver.queryProviders(intent, resolvedType, flags, userId), instantAppPkgName); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return applyPostContentProviderResolutionFilter( - mProviders.queryIntentForPackage( - intent, resolvedType, flags, pkg.providers, userId), + mComponentResolver.queryProviders(intent, resolvedType, flags, + pkg.providers, userId), instantAppPkgName); } return Collections.emptyList(); @@ -8332,25 +8323,21 @@ public class PackageManagerService extends IPackageManager.Stub if (!sUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, name); final int callingUid = Binder.getCallingUid(); + final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); + if (providerInfo == null) { + return null; + } + if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) { + return null; + } synchronized (mPackages) { - final PackageParser.Provider provider = mProvidersByAuthority.get(name); - PackageSetting ps = provider != null - ? mSettings.mPackages.get(provider.owner.packageName) - : null; - if (ps != null) { - // provider not enabled - if (!mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)) { - return null; - } - final ComponentName component = - new ComponentName(provider.info.packageName, provider.info.name); - if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) { - return null; - } - return PackageParser.generateProviderInfo( - provider, flags, ps.readUserState(userId), userId); + final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName); + final ComponentName component = + new ComponentName(providerInfo.packageName, providerInfo.name); + if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) { + return null; } - return null; + return providerInfo; } } @@ -8362,28 +8349,8 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } - // reader - synchronized (mPackages) { - final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProvidersByAuthority - .entrySet().iterator(); - final int userId = UserHandle.getCallingUserId(); - while (i.hasNext()) { - Map.Entry<String, PackageParser.Provider> entry = i.next(); - PackageParser.Provider p = entry.getValue(); - PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); - - if (ps != null && p.syncable - && (!mSafeMode || (p.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { - ProviderInfo info = PackageParser.generateProviderInfo(p, 0, - ps.readUserState(userId), userId); - if (info != null) { - outNames.add(entry.getKey()); - outInfo.add(info); - } - } - } - } + mComponentResolver.querySyncProviders( + outNames, outInfo, mSafeMode, UserHandle.getCallingUserId()); } @Override @@ -8395,43 +8362,30 @@ public class PackageManagerService extends IPackageManager.Stub if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForComponent(flags, userId, processName); ArrayList<ProviderInfo> finalList = null; - // reader + final List<ProviderInfo> matchList = + mComponentResolver.queryProviders(processName, metaDataKey, uid, flags, userId); + final int listSize = (matchList == null ? 0 : matchList.size()); synchronized (mPackages) { - final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator(); - while (i.hasNext()) { - final PackageParser.Provider p = i.next(); - PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); - if (ps != null && p.info.authority != null - && (processName == null - || (p.info.processName.equals(processName) - && UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) - && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) { - - // See PM.queryContentProviders()'s javadoc for why we have the metaData - // parameter. - if (metaDataKey != null - && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) { - continue; - } - final ComponentName component = - new ComponentName(p.info.packageName, p.info.name); - if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) { - continue; - } - if (finalList == null) { - finalList = new ArrayList<>(3); - } - ProviderInfo info = PackageParser.generateProviderInfo(p, flags, - ps.readUserState(userId), userId); - if (info != null) { - finalList.add(info); - } + for (int i = 0; i < listSize; i++) { + final ProviderInfo providerInfo = matchList.get(i); + if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) { + continue; + } + final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName); + final ComponentName component = + new ComponentName(providerInfo.packageName, providerInfo.name); + if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) { + continue; } + if (finalList == null) { + finalList = new ArrayList<>(listSize - i); + } + finalList.add(providerInfo); } } if (finalList != null) { - finalList.sort(mProviderInitOrderSorter); + finalList.sort(sProviderInitOrderSorter); return new ParceledListSlice<>(finalList); } @@ -8914,15 +8868,16 @@ public class PackageManagerService extends IPackageManager.Stub + " better than this " + pkg.getLongVersionCode()); } - // Verify certificates against what was last scanned. If there was an upgrade or this is an - // updated priv app, we will force re-collecting certificate. - final boolean forceCollect = mIsUpgrade || - PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting); + // Verify certificates against what was last scanned. If there was an upgrade and this is an + // app in a system partition, or if this is an updated priv app, we will force re-collecting + // certificate. + final boolean forceCollect = (mIsUpgrade && scanSystemPartition) + || PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting); // Full APK verification can be skipped during certificate collection, only if the file is // in verified partition, or can be verified on access (when apk verity is enabled). In both // cases, only data in Signing Block is verified instead of the whole file. - final boolean skipVerify = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) || - (forceCollect && canSkipFullPackageVerification(pkg)); + final boolean skipVerify = scanSystemPartition + || (forceCollect && canSkipFullPackageVerification(pkg)); collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify); // Reset profile if the application version is changed @@ -9001,8 +8956,7 @@ public class PackageManagerService extends IPackageManager.Stub + pkg.staticSharedLibVersion); } - private static String fixProcessName(String defProcessName, - String processName) { + static String fixProcessName(String defProcessName, String processName) { if (processName == null) { return defProcessName; } @@ -10166,6 +10120,7 @@ public class PackageManagerService extends IPackageManager.Stub * <li>{@link #SCAN_AS_OEM}</li> * <li>{@link #SCAN_AS_VENDOR}</li> * <li>{@link #SCAN_AS_PRODUCT}</li> + * <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li> * <li>{@link #SCAN_AS_INSTANT_APP}</li> * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li> * </ul> @@ -10192,6 +10147,10 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) { scanFlags |= SCAN_AS_PRODUCT; } + if ((disabledPkgSetting.pkgPrivateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) { + scanFlags |= SCAN_AS_PRODUCT_SERVICES; + } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); @@ -11034,6 +10993,10 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT; } + if ((scanFlags & SCAN_AS_PRODUCT_SERVICES) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; + } + // Check if the package is signed with the same key as the platform package. if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) || (platformPkg != null && compareSignatures( @@ -11287,27 +11250,7 @@ public class PackageManagerService extends IPackageManager.Stub // package isn't already installed, since we don't want to break // things that are installed. if ((scanFlags & SCAN_NEW_INSTALL) != 0) { - final int N = pkg.providers.size(); - int i; - for (i=0; i<N; i++) { - PackageParser.Provider p = pkg.providers.get(i); - if (p.info.authority != null) { - String names[] = p.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - if (mProvidersByAuthority.containsKey(names[j])) { - PackageParser.Provider other = mProvidersByAuthority.get(names[j]); - final String otherPackageName = - ((other != null && other.getComponentName() != null) ? - other.getComponentName().getPackageName() : "?"); - throw new PackageManagerException( - INSTALL_FAILED_CONFLICTING_PROVIDER, - "Can't install because provider name " + names[j] - + " (in package " + pkg.applicationInfo.packageName - + ") is already used by " + otherPackageName); - } - } - } - } + mComponentResolver.assertProvidersNotDefined(pkg); } // Verify that packages sharing a user with a privileged app are marked as privileged. @@ -11605,125 +11548,7 @@ public class PackageManagerService extends IPackageManager.Stub KeySetManagerService ksms = mSettings.mKeySetManagerService; ksms.addScannedPackageLPw(pkg); - int N = pkg.providers.size(); - StringBuilder r = null; - int i; - for (i=0; i<N; i++) { - PackageParser.Provider p = pkg.providers.get(i); - p.info.processName = fixProcessName(pkg.applicationInfo.processName, - p.info.processName); - mProviders.addProvider(p); - p.syncable = p.info.isSyncable; - if (p.info.authority != null) { - String names[] = p.info.authority.split(";"); - p.info.authority = null; - for (int j = 0; j < names.length; j++) { - if (j == 1 && p.syncable) { - // We only want the first authority for a provider to possibly be - // syncable, so if we already added this provider using a different - // authority clear the syncable flag. We copy the provider before - // changing it because the mProviders object contains a reference - // to a provider that we don't want to change. - // Only do this for the second authority since the resulting provider - // object can be the same for all future authorities for this provider. - p = new PackageParser.Provider(p); - p.syncable = false; - } - if (!mProvidersByAuthority.containsKey(names[j])) { - mProvidersByAuthority.put(names[j], p); - if (p.info.authority == null) { - p.info.authority = names[j]; - } else { - p.info.authority = p.info.authority + ";" + names[j]; - } - if (DEBUG_PACKAGE_SCANNING) { - if (chatty) - Log.d(TAG, "Registered content provider: " + names[j] - + ", className = " + p.info.name + ", isSyncable = " - + p.info.isSyncable); - } - } else { - PackageParser.Provider other = mProvidersByAuthority.get(names[j]); - Slog.w(TAG, "Skipping provider name " + names[j] + - " (in package " + pkg.applicationInfo.packageName + - "): name already used by " - + ((other != null && other.getComponentName() != null) - ? other.getComponentName().getPackageName() : "?")); - } - } - } - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - if (r != null) { - if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r); - } - - N = pkg.services.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Service s = pkg.services.get(i); - s.info.processName = fixProcessName(pkg.applicationInfo.processName, - s.info.processName); - mServices.addService(s); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(s.info.name); - } - } - if (r != null) { - if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r); - } - - N = pkg.receivers.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName); - mReceivers.addActivity(a, "receiver"); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); - } - - N = pkg.activities.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.activities.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName); - mActivities.addActivity(a, "activity"); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); - } + mComponentResolver.addAllComponents(pkg, chatty); // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { @@ -11741,9 +11566,10 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.addAllPermissions(pkg, chatty); } - N = pkg.instrumentation.size(); - r = null; - for (i=0; i<N; i++) { + int collectionSize = pkg.instrumentation.size(); + StringBuilder r = null; + int i; + for (i = 0; i < collectionSize; i++) { PackageParser.Instrumentation a = pkg.instrumentation.get(i); a.info.packageName = pkg.applicationInfo.packageName; a.info.sourceDir = pkg.applicationInfo.sourceDir; @@ -11774,9 +11600,9 @@ public class PackageManagerService extends IPackageManager.Stub } if (pkg.protectedBroadcasts != null) { - N = pkg.protectedBroadcasts.size(); + collectionSize = pkg.protectedBroadcasts.size(); synchronized (mProtectedBroadcasts) { - for (i = 0; i < N; i++) { + for (i = 0; i < collectionSize; i++) { mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); } } @@ -12127,6 +11953,8 @@ public class PackageManagerService extends IPackageManager.Stub codeRoot = Environment.getOdmDirectory(); } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) { codeRoot = Environment.getProductDirectory(); + } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) { + codeRoot = Environment.getProductServicesDirectory(); } else { // Unrecognized code path; take its top real segment as the apk root: // e.g. /something/app/blah.apk => /something @@ -12393,105 +12221,15 @@ public class PackageManagerService extends IPackageManager.Stub } void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) { - int N = pkg.providers.size(); - StringBuilder r = null; - int i; - for (i=0; i<N; i++) { - PackageParser.Provider p = pkg.providers.get(i); - mProviders.removeProvider(p); - if (p.info.authority == null) { - - /* There was another ContentProvider with this authority when - * this app was installed so this authority is null, - * Ignore it as we don't have to unregister the provider. - */ - continue; - } - String names[] = p.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - if (mProvidersByAuthority.get(names[j]) == p) { - mProvidersByAuthority.remove(names[j]); - if (DEBUG_REMOVE) { - if (chatty) - Log.d(TAG, "Unregistered content provider: " + names[j] - + ", className = " + p.info.name + ", isSyncable = " - + p.info.isSyncable); - } - } - } - if (DEBUG_REMOVE && chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - if (r != null) { - if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r); - } - - N = pkg.services.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Service s = pkg.services.get(i); - mServices.removeService(s); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(s.info.name); - } - } - if (r != null) { - if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r); - } - - N = pkg.receivers.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - mReceivers.removeActivity(a, "receiver"); - if (DEBUG_REMOVE && chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r); - } - - N = pkg.activities.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.activities.get(i); - mActivities.removeActivity(a, "activity"); - if (DEBUG_REMOVE && chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r); - } + mComponentResolver.removeAllComponents(pkg, chatty); final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet()); mPermissionManager.removeAllPermissions(pkg, allPackageNames, mPermissionCallback, chatty); - N = pkg.instrumentation.size(); - r = null; - for (i=0; i<N; i++) { + final int instrumentationSize = pkg.instrumentation.size(); + StringBuilder r = null; + int i; + for (i = 0; i < instrumentationSize; i++) { PackageParser.Instrumentation a = pkg.instrumentation.get(i); mInstrumentation.remove(a.getComponentName()); if (DEBUG_REMOVE && chatty) { @@ -12511,7 +12249,8 @@ public class PackageManagerService extends IPackageManager.Stub if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { // Only system apps can hold shared libraries. if (pkg.libraryNames != null) { - for (i = 0; i < pkg.libraryNames.size(); i++) { + final int libraryNamesSize = pkg.libraryNames.size(); + for (i = 0; i < libraryNamesSize; i++) { String name = pkg.libraryNames.get(i); if (removeSharedLibraryLPw(name, 0)) { if (DEBUG_REMOVE && chatty) { @@ -12548,1135 +12287,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - - final class ActivityIntentResolver - extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, - boolean defaultOnly, int userId) { - if (!sUserManager.exists(userId)) return null; - mFlags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0); - return super.queryIntent(intent, resolvedType, defaultOnly, userId); - } - - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, - int userId) { - if (!sUserManager.exists(userId)) return null; - mFlags = flags; - return super.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId); - } - - public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) { - if (!sUserManager.exists(userId)) return null; - if (packageActivities == null) { - return null; - } - mFlags = flags; - final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; - final int N = packageActivities.size(); - ArrayList<PackageParser.ActivityIntentInfo[]> listCut = - new ArrayList<PackageParser.ActivityIntentInfo[]>(N); - - ArrayList<PackageParser.ActivityIntentInfo> intentFilters; - for (int i = 0; i < N; ++i) { - intentFilters = packageActivities.get(i).intents; - if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ActivityIntentInfo[] array = - new PackageParser.ActivityIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); - listCut.add(array); - } - } - return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); - } - - /** - * Finds a privileged activity that matches the specified activity names. - */ - private PackageParser.Activity findMatchingActivity( - List<PackageParser.Activity> activityList, ActivityInfo activityInfo) { - for (PackageParser.Activity sysActivity : activityList) { - if (sysActivity.info.name.equals(activityInfo.name)) { - return sysActivity; - } - if (sysActivity.info.name.equals(activityInfo.targetActivity)) { - return sysActivity; - } - if (sysActivity.info.targetActivity != null) { - if (sysActivity.info.targetActivity.equals(activityInfo.name)) { - return sysActivity; - } - if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) { - return sysActivity; - } - } - } - return null; - } - - public class IterGenerator<E> { - public Iterator<E> generate(ActivityIntentInfo info) { - return null; - } - } - - public class ActionIterGenerator extends IterGenerator<String> { - @Override - public Iterator<String> generate(ActivityIntentInfo info) { - return info.actionsIterator(); - } - } - - public class CategoriesIterGenerator extends IterGenerator<String> { - @Override - public Iterator<String> generate(ActivityIntentInfo info) { - return info.categoriesIterator(); - } - } - - public class SchemesIterGenerator extends IterGenerator<String> { - @Override - public Iterator<String> generate(ActivityIntentInfo info) { - return info.schemesIterator(); - } - } - - public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { - @Override - public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) { - return info.authoritiesIterator(); - } - } - - /** - * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE - * MODIFIED. Do not pass in a list that should not be changed. - */ - private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList, - IterGenerator<T> generator, Iterator<T> searchIterator) { - // loop through the set of actions; every one must be found in the intent filter - while (searchIterator.hasNext()) { - // we must have at least one filter in the list to consider a match - if (intentList.size() == 0) { - break; - } - - final T searchAction = searchIterator.next(); - - // loop through the set of intent filters - final Iterator<ActivityIntentInfo> intentIter = intentList.iterator(); - while (intentIter.hasNext()) { - final ActivityIntentInfo intentInfo = intentIter.next(); - boolean selectionFound = false; - - // loop through the intent filter's selection criteria; at least one - // of them must match the searched criteria - final Iterator<T> intentSelectionIter = generator.generate(intentInfo); - while (intentSelectionIter != null && intentSelectionIter.hasNext()) { - final T intentSelection = intentSelectionIter.next(); - if (intentSelection != null && intentSelection.equals(searchAction)) { - selectionFound = true; - break; - } - } - - // the selection criteria wasn't found in this filter's set; this filter - // is not a potential match - if (!selectionFound) { - intentIter.remove(); - } - } - } - } - - private boolean isProtectedAction(ActivityIntentInfo filter) { - final Iterator<String> actionsIter = filter.actionsIterator(); - while (actionsIter != null && actionsIter.hasNext()) { - final String filterAction = actionsIter.next(); - if (PROTECTED_ACTIONS.contains(filterAction)) { - return true; - } - } - return false; - } - - /** - * Adjusts the priority of the given intent filter according to policy. - * <p> - * <ul> - * <li>The priority for non privileged applications is capped to '0'</li> - * <li>The priority for protected actions on privileged applications is capped to '0'</li> - * <li>The priority for unbundled updates to privileged applications is capped to the - * priority defined on the system partition</li> - * </ul> - * <p> - * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is - * allowed to obtain any priority on any action. - */ - private void adjustPriority( - List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) { - // nothing to do; priority is fine as-is - if (intent.getPriority() <= 0) { - return; - } - - final ActivityInfo activityInfo = intent.activity.info; - final ApplicationInfo applicationInfo = activityInfo.applicationInfo; - - final boolean privilegedApp = - ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); - if (!privilegedApp) { - // non-privileged applications can never define a priority >0 - if (DEBUG_FILTERS) { - Slog.i(TAG, "Non-privileged app; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - - if (systemActivities == null) { - // the system package is not disabled; we're parsing the system partition - if (isProtectedAction(intent)) { - if (mDeferProtectedFilters) { - // We can't deal with these just yet. No component should ever obtain a - // >0 priority for a protected actions, with ONE exception -- the setup - // wizard. The setup wizard, however, cannot be known until we're able to - // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do - // until all intent filters have been processed. Chicken, meet egg. - // Let the filter temporarily have a high priority and rectify the - // priorities after all system packages have been scanned. - mProtectedFilters.add(intent); - if (DEBUG_FILTERS) { - Slog.i(TAG, "Protected action; save for later;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - return; - } else { - if (DEBUG_FILTERS && mSetupWizardPackage == null) { - Slog.i(TAG, "No setup wizard;" - + " All protected intents capped to priority 0"); - } - if (intent.activity.info.packageName.equals(mSetupWizardPackage)) { - if (DEBUG_FILTERS) { - Slog.i(TAG, "Found setup wizard;" - + " allow priority " + intent.getPriority() + ";" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className - + " priority: " + intent.getPriority()); - } - // setup wizard gets whatever it wants - return; - } - if (DEBUG_FILTERS) { - Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - } - // privileged apps on the system image get whatever priority they request - return; - } - - // privileged app unbundled update ... try to find the same activity - final PackageParser.Activity foundActivity = - findMatchingActivity(systemActivities, activityInfo); - if (foundActivity == null) { - // this is a new activity; it cannot obtain >0 priority - if (DEBUG_FILTERS) { - Slog.i(TAG, "New activity; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - - // found activity, now check for filter equivalence - - // a shallow copy is enough; we modify the list, not its contents - final List<ActivityIntentInfo> intentListCopy = - new ArrayList<>(foundActivity.intents); - final List<ActivityIntentInfo> foundFilters = findFilters(intent); - - // find matching action subsets - final Iterator<String> actionsIterator = intent.actionsIterator(); - if (actionsIterator != null) { - getIntentListSubset( - intentListCopy, new ActionIterGenerator(), actionsIterator); - if (intentListCopy.size() == 0) { - // no more intents to match; we're not equivalent - if (DEBUG_FILTERS) { - Slog.i(TAG, "Mismatched action; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - } - - // find matching category subsets - final Iterator<String> categoriesIterator = intent.categoriesIterator(); - if (categoriesIterator != null) { - getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), - categoriesIterator); - if (intentListCopy.size() == 0) { - // no more intents to match; we're not equivalent - if (DEBUG_FILTERS) { - Slog.i(TAG, "Mismatched category; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - } - - // find matching schemes subsets - final Iterator<String> schemesIterator = intent.schemesIterator(); - if (schemesIterator != null) { - getIntentListSubset(intentListCopy, new SchemesIterGenerator(), - schemesIterator); - if (intentListCopy.size() == 0) { - // no more intents to match; we're not equivalent - if (DEBUG_FILTERS) { - Slog.i(TAG, "Mismatched scheme; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - } - - // find matching authorities subsets - final Iterator<IntentFilter.AuthorityEntry> - authoritiesIterator = intent.authoritiesIterator(); - if (authoritiesIterator != null) { - getIntentListSubset(intentListCopy, - new AuthoritiesIterGenerator(), - authoritiesIterator); - if (intentListCopy.size() == 0) { - // no more intents to match; we're not equivalent - if (DEBUG_FILTERS) { - Slog.i(TAG, "Mismatched authority; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(0); - return; - } - } - - // we found matching filter(s); app gets the max priority of all intents - int cappedPriority = 0; - for (int i = intentListCopy.size() - 1; i >= 0; --i) { - cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority()); - } - if (intent.getPriority() > cappedPriority) { - if (DEBUG_FILTERS) { - Slog.i(TAG, "Found matching filter(s);" - + " cap priority to " + cappedPriority + ";" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className - + " origPrio: " + intent.getPriority()); - } - intent.setPriority(cappedPriority); - return; - } - // all this for nothing; the requested priority was <= what was on the system - } - - public final void addActivity(PackageParser.Activity a, String type) { - mActivities.put(a.getComponentName(), a); - if (DEBUG_SHOW_INFO) - Log.v( - TAG, " " + type + " " + - (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":"); - if (DEBUG_SHOW_INFO) - Log.v(TAG, " Class=" + a.info.name); - final int NI = a.intents.size(); - for (int j=0; j<NI; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if ("activity".equals(type)) { - final PackageSetting ps = - mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName); - final List<PackageParser.Activity> systemActivities = - ps != null && ps.pkg != null ? ps.pkg.activities : null; - adjustPriority(systemActivities, intent); - } - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - if (!intent.debugCheck()) { - Log.w(TAG, "==> For Activity " + a.info.name); - } - addFilter(intent); - } - } - - public final void removeActivity(PackageParser.Activity a, String type) { - mActivities.remove(a.getComponentName()); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + type + " " - + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel - : a.info.name) + ":"); - Log.v(TAG, " Class=" + a.info.name); - } - final int NI = a.intents.size(); - for (int j=0; j<NI; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - removeFilter(intent); - } - } - - @Override - protected boolean allowFilterResult( - PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) { - ActivityInfo filterAi = filter.activity.info; - for (int i=dest.size()-1; i>=0; i--) { - ActivityInfo destAi = dest.get(i).activityInfo; - if (destAi.name == filterAi.name - && destAi.packageName == filterAi.packageName) { - return false; - } - } - return true; - } - - @Override - protected ActivityIntentInfo[] newArray(int size) { - return new ActivityIntentInfo[size]; - } - - @Override - protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.activity.owner; - if (p != null) { - PackageSetting ps = (PackageSetting)p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } - } - return false; - } - - @Override - protected boolean isPackageForFilter(String packageName, - PackageParser.ActivityIntentInfo info) { - return packageName.equals(info.activity.owner.packageName); - } - - @Override - protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, - int match, int userId) { - if (!sUserManager.exists(userId)) return null; - if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) { - return null; - } - final PackageParser.Activity activity = info.activity; - PackageSetting ps = (PackageSetting) activity.owner.mExtras; - if (ps == null) { - return null; - } - final PackageUserState userState = ps.readUserState(userId); - ActivityInfo ai = - PackageParser.generateActivityInfo(activity, mFlags, userState, userId); - if (ai == null) { - return null; - } - final boolean matchExplicitlyVisibleOnly = - (mFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; - final boolean matchVisibleToInstantApp = - (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; - final boolean componentVisible = - matchVisibleToInstantApp - && info.isVisibleToInstantApp() - && (!matchExplicitlyVisibleOnly || info.isExplicitlyVisibleToInstantApp()); - final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; - // throw out filters that aren't visible to ephemeral apps - if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) { - return null; - } - // throw out instant app filters if we're not explicitly requesting them - if (!matchInstantApp && userState.instantApp) { - return null; - } - // throw out instant app filters if updates are available; will trigger - // instant app resolution - if (userState.instantApp && ps.isUpdateAvailable()) { - return null; - } - final ResolveInfo res = new ResolveInfo(); - res.activityInfo = ai; - if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { - res.filter = info; - } - res.handleAllWebDataURI = info.handleAllWebDataURI(); - res.priority = info.getPriority(); - res.preferredOrder = activity.owner.mPreferredOrder; - //System.out.println("Result: " + res.activityInfo.className + - // " = " + res.priority); - res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - if (userNeedsBadging(userId)) { - res.noResourceId = true; - } else { - res.icon = info.icon; - } - res.iconResourceId = info.icon; - res.system = res.activityInfo.applicationInfo.isSystemApp(); - res.isInstantAppAvailable = userState.instantApp; - return res; - } - - @Override - protected void sortResults(List<ResolveInfo> results) { - results.sort(mResolvePrioritySorter); - } - - @Override - protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ActivityIntentInfo filter) { - out.print(prefix); out.print( - Integer.toHexString(System.identityHashCode(filter.activity))); - out.print(' '); - filter.activity.printComponentShortName(out); - out.print(" filter "); - out.println(Integer.toHexString(System.identityHashCode(filter))); - } - - @Override - protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) { - return filter.activity; - } - - protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - PackageParser.Activity activity = (PackageParser.Activity)label; - out.print(prefix); out.print( - Integer.toHexString(System.identityHashCode(activity))); - out.print(' '); - activity.printComponentShortName(out); - if (count > 1) { - out.print(" ("); out.print(count); out.print(" filters)"); - } - out.println(); - } - - // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Activity> mActivities - = new ArrayMap<>(); - private int mFlags; - } - - private final class ServiceIntentResolver - extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, - boolean defaultOnly, int userId) { - mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(intent, resolvedType, defaultOnly, userId); - } - - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, - int userId) { - if (!sUserManager.exists(userId)) return null; - mFlags = flags; - return super.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId); - } - - public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, ArrayList<PackageParser.Service> packageServices, int userId) { - if (!sUserManager.exists(userId)) return null; - if (packageServices == null) { - return null; - } - mFlags = flags; - final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0; - final int N = packageServices.size(); - ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(N); - - ArrayList<PackageParser.ServiceIntentInfo> intentFilters; - for (int i = 0; i < N; ++i) { - intentFilters = packageServices.get(i).intents; - if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ServiceIntentInfo[] array = - new PackageParser.ServiceIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); - listCut.add(array); - } - } - return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); - } - - public final void addService(PackageParser.Service s) { - mServices.put(s.getComponentName(), s); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " - + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); - } - final int NI = s.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - if (!intent.debugCheck()) { - Log.w(TAG, "==> For Service " + s.info.name); - } - addFilter(intent); - } - } - - public final void removeService(PackageParser.Service s) { - mServices.remove(s.getComponentName()); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); - } - final int NI = s.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - removeFilter(intent); - } - } - - @Override - protected boolean allowFilterResult( - PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) { - ServiceInfo filterSi = filter.service.info; - for (int i=dest.size()-1; i>=0; i--) { - ServiceInfo destAi = dest.get(i).serviceInfo; - if (destAi.name == filterSi.name - && destAi.packageName == filterSi.packageName) { - return false; - } - } - return true; - } - - @Override - protected PackageParser.ServiceIntentInfo[] newArray(int size) { - return new PackageParser.ServiceIntentInfo[size]; - } - - @Override - protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.service.owner; - if (p != null) { - PackageSetting ps = (PackageSetting)p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } - } - return false; - } - - @Override - protected boolean isPackageForFilter(String packageName, - PackageParser.ServiceIntentInfo info) { - return packageName.equals(info.service.owner.packageName); - } - - @Override - protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, - int match, int userId) { - if (!sUserManager.exists(userId)) return null; - final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; - if (!mSettings.isEnabledAndMatchLPr(info.service.info, mFlags, userId)) { - return null; - } - final PackageParser.Service service = info.service; - PackageSetting ps = (PackageSetting) service.owner.mExtras; - if (ps == null) { - return null; - } - final PackageUserState userState = ps.readUserState(userId); - ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags, - userState, userId); - if (si == null) { - return null; - } - final boolean matchVisibleToInstantApp = - (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; - final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; - // throw out filters that aren't visible to ephemeral apps - if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { - return null; - } - // throw out ephemeral filters if we're not explicitly requesting them - if (!isInstantApp && userState.instantApp) { - return null; - } - // throw out instant app filters if updates are available; will trigger - // instant app resolution - if (userState.instantApp && ps.isUpdateAvailable()) { - return null; - } - final ResolveInfo res = new ResolveInfo(); - res.serviceInfo = si; - if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { - res.filter = filter; - } - res.priority = info.getPriority(); - res.preferredOrder = service.owner.mPreferredOrder; - res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; - res.system = res.serviceInfo.applicationInfo.isSystemApp(); - return res; - } - - @Override - protected void sortResults(List<ResolveInfo> results) { - results.sort(mResolvePrioritySorter); - } - - @Override - protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ServiceIntentInfo filter) { - out.print(prefix); out.print( - Integer.toHexString(System.identityHashCode(filter.service))); - out.print(' '); - filter.service.printComponentShortName(out); - out.print(" filter "); - out.print(Integer.toHexString(System.identityHashCode(filter))); - if (filter.service.info.permission != null) { - out.print(" permission "); out.println(filter.service.info.permission); - } else { - out.println(); - } - } - - @Override - protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) { - return filter.service; - } - - protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - PackageParser.Service service = (PackageParser.Service)label; - out.print(prefix); out.print( - Integer.toHexString(System.identityHashCode(service))); - out.print(' '); - service.printComponentShortName(out); - if (count > 1) { - out.print(" ("); out.print(count); out.print(" filters)"); - } - out.println(); - } - -// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { -// final Iterator<ResolveInfo> i = resolveInfoList.iterator(); -// final List<ResolveInfo> retList = Lists.newArrayList(); -// while (i.hasNext()) { -// final ResolveInfo resolveInfo = (ResolveInfo) i; -// if (isEnabledLP(resolveInfo.serviceInfo)) { -// retList.add(resolveInfo); -// } -// } -// return retList; -// } - - // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>(); - private int mFlags; - } - - private final class ProviderIntentResolver - extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> { - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, - boolean defaultOnly, int userId) { - mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(intent, resolvedType, defaultOnly, userId); - } - - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, - int userId) { - if (!sUserManager.exists(userId)) - return null; - mFlags = flags; - return super.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId); - } - - public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, ArrayList<PackageParser.Provider> packageProviders, int userId) { - if (!sUserManager.exists(userId)) - return null; - if (packageProviders == null) { - return null; - } - mFlags = flags; - final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; - final int N = packageProviders.size(); - ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(N); - - ArrayList<PackageParser.ProviderIntentInfo> intentFilters; - for (int i = 0; i < N; ++i) { - intentFilters = packageProviders.get(i).intents; - if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ProviderIntentInfo[] array = - new PackageParser.ProviderIntentInfo[intentFilters.size()]; - intentFilters.toArray(array); - listCut.add(array); - } - } - return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); - } - - public final void addProvider(PackageParser.Provider p) { - if (mProviders.containsKey(p.getComponentName())) { - Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring"); - return; - } - - mProviders.put(p.getComponentName(), p); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " - + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel : p.info.name) + ":"); - Log.v(TAG, " Class=" + p.info.name); - } - final int NI = p.intents.size(); - int j; - for (j = 0; j < NI; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - if (!intent.debugCheck()) { - Log.w(TAG, "==> For Provider " + p.info.name); - } - addFilter(intent); - } - } - - public final void removeProvider(PackageParser.Provider p) { - mProviders.remove(p.getComponentName()); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel : p.info.name) + ":"); - Log.v(TAG, " Class=" + p.info.name); - } - final int NI = p.intents.size(); - int j; - for (j = 0; j < NI; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); - if (DEBUG_SHOW_INFO) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - removeFilter(intent); - } - } - - @Override - protected boolean allowFilterResult( - PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) { - ProviderInfo filterPi = filter.provider.info; - for (int i = dest.size() - 1; i >= 0; i--) { - ProviderInfo destPi = dest.get(i).providerInfo; - if (destPi.name == filterPi.name - && destPi.packageName == filterPi.packageName) { - return false; - } - } - return true; - } - - @Override - protected PackageParser.ProviderIntentInfo[] newArray(int size) { - return new PackageParser.ProviderIntentInfo[size]; - } - - @Override - protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) { - if (!sUserManager.exists(userId)) - return true; - PackageParser.Package p = filter.provider.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } - } - return false; - } - - @Override - protected boolean isPackageForFilter(String packageName, - PackageParser.ProviderIntentInfo info) { - return packageName.equals(info.provider.owner.packageName); - } - - @Override - protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter, - int match, int userId) { - if (!sUserManager.exists(userId)) - return null; - final PackageParser.ProviderIntentInfo info = filter; - if (!mSettings.isEnabledAndMatchLPr(info.provider.info, mFlags, userId)) { - return null; - } - final PackageParser.Provider provider = info.provider; - PackageSetting ps = (PackageSetting) provider.owner.mExtras; - if (ps == null) { - return null; - } - final PackageUserState userState = ps.readUserState(userId); - final boolean matchVisibleToInstantApp = - (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; - final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; - // throw out filters that aren't visible to instant applications - if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { - return null; - } - // throw out instant application filters if we're not explicitly requesting them - if (!isInstantApp && userState.instantApp) { - return null; - } - // throw out instant application filters if updates are available; will trigger - // instant application resolution - if (userState.instantApp && ps.isUpdateAvailable()) { - return null; - } - ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags, - userState, userId); - if (pi == null) { - return null; - } - final ResolveInfo res = new ResolveInfo(); - res.providerInfo = pi; - if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { - res.filter = filter; - } - res.priority = info.getPriority(); - res.preferredOrder = provider.owner.mPreferredOrder; - res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; - res.system = res.providerInfo.applicationInfo.isSystemApp(); - return res; - } - - @Override - protected void sortResults(List<ResolveInfo> results) { - results.sort(mResolvePrioritySorter); - } - - @Override - protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ProviderIntentInfo filter) { - out.print(prefix); - out.print( - Integer.toHexString(System.identityHashCode(filter.provider))); - out.print(' '); - filter.provider.printComponentShortName(out); - out.print(" filter "); - out.println(Integer.toHexString(System.identityHashCode(filter))); - } - - @Override - protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) { - return filter.provider; - } - - protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - PackageParser.Provider provider = (PackageParser.Provider)label; - out.print(prefix); out.print( - Integer.toHexString(System.identityHashCode(provider))); - out.print(' '); - provider.printComponentShortName(out); - if (count > 1) { - out.print(" ("); out.print(count); out.print(" filters)"); - } - out.println(); - } - - private final ArrayMap<ComponentName, PackageParser.Provider> mProviders - = new ArrayMap<>(); - private int mFlags; - } - - static final class InstantAppIntentResolver - extends IntentResolver<AuxiliaryResolveInfo.AuxiliaryFilter, - AuxiliaryResolveInfo.AuxiliaryFilter> { - /** - * The result that has the highest defined order. Ordering applies on a - * per-package basis. Mapping is from package name to Pair of order and - * EphemeralResolveInfo. - * <p> - * NOTE: This is implemented as a field variable for convenience and efficiency. - * By having a field variable, we're able to track filter ordering as soon as - * a non-zero order is defined. Otherwise, multiple loops across the result set - * would be needed to apply ordering. If the intent resolver becomes re-entrant, - * this needs to be contained entirely within {@link #filterResults}. - */ - final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = new ArrayMap<>(); - - @Override - protected AuxiliaryResolveInfo.AuxiliaryFilter[] newArray(int size) { - return new AuxiliaryResolveInfo.AuxiliaryFilter[size]; - } - - @Override - protected boolean isPackageForFilter(String packageName, - AuxiliaryResolveInfo.AuxiliaryFilter responseObj) { - return true; - } - - @Override - protected AuxiliaryResolveInfo.AuxiliaryFilter newResult( - AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId) { - if (!sUserManager.exists(userId)) { - return null; - } - final String packageName = responseObj.resolveInfo.getPackageName(); - final Integer order = responseObj.getOrder(); - final Pair<Integer, InstantAppResolveInfo> lastOrderResult = - mOrderResult.get(packageName); - // ordering is enabled and this item's order isn't high enough - if (lastOrderResult != null && lastOrderResult.first >= order) { - return null; - } - final InstantAppResolveInfo res = responseObj.resolveInfo; - if (order > 0) { - // non-zero order, enable ordering - mOrderResult.put(packageName, new Pair<>(order, res)); - } - return responseObj; - } - - @Override - protected void filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results) { - // only do work if ordering is enabled [most of the time it won't be] - if (mOrderResult.size() == 0) { - return; - } - int resultSize = results.size(); - for (int i = 0; i < resultSize; i++) { - final InstantAppResolveInfo info = results.get(i).resolveInfo; - final String packageName = info.getPackageName(); - final Pair<Integer, InstantAppResolveInfo> savedInfo = mOrderResult.get(packageName); - if (savedInfo == null) { - // package doesn't having ordering - continue; - } - if (savedInfo.second == info) { - // circled back to the highest ordered item; remove from order list - mOrderResult.remove(packageName); - if (mOrderResult.size() == 0) { - // no more ordered items - break; - } - continue; - } - // item has a worse order, remove it from the result list - results.remove(i); - resultSize--; - i--; - } - } - } - - private static final Comparator<ResolveInfo> mResolvePrioritySorter = (r1, r2) -> { - int v1 = r1.priority; - int v2 = r2.priority; - //System.out.println("Comparing: q1=" + q1 + " q2=" + q2); - if (v1 != v2) { - return (v1 > v2) ? -1 : 1; - } - v1 = r1.preferredOrder; - v2 = r2.preferredOrder; - if (v1 != v2) { - return (v1 > v2) ? -1 : 1; - } - if (r1.isDefault != r2.isDefault) { - return r1.isDefault ? -1 : 1; - } - v1 = r1.match; - v2 = r2.match; - //System.out.println("Comparing: m1=" + m1 + " m2=" + m2); - if (v1 != v2) { - return (v1 > v2) ? -1 : 1; - } - if (r1.system != r2.system) { - return r1.system ? -1 : 1; - } - if (r1.activityInfo != null) { - return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName); - } - if (r1.serviceInfo != null) { - return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName); - } - if (r1.providerInfo != null) { - return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName); - } - return 0; - }; - - private static final Comparator<ProviderInfo> mProviderInitOrderSorter = (p1, p2) -> { - final int v1 = p1.initOrder; - final int v2 = p2.initOrder; - return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0); - }; - @Override public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, @@ -13716,6 +12326,12 @@ public class PackageManagerService extends IPackageManager.Stub } } + private static final Comparator<ProviderInfo> sProviderInitOrderSorter = (p1, p2) -> { + final int v1 = p1.initOrder; + final int v2 = p2.initOrder; + return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0); + }; + @Override public void notifyPackageRemoved(String packageName) { final PackageListObserver[] observers; @@ -14169,11 +12785,12 @@ public class PackageManagerService extends IPackageManager.Stub info.sendPackageRemovedBroadcasts(true /*killApp*/); } - private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended, - PersistableBundle launcherExtras) { + private void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId, + boolean suspended, PersistableBundle launcherExtras) { if (pkgList.length > 0) { Bundle extras = new Bundle(1); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList); if (launcherExtras != null) { extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS, new Bundle(launcherExtras.deepCopy())); @@ -14355,6 +12972,7 @@ public class PackageManagerService extends IPackageManager.Stub } final List<String> changedPackagesList = new ArrayList<>(packageNames.length); + final IntArray changedUids = new IntArray(packageNames.length); final List<String> unactionedPackages = new ArrayList<>(packageNames.length); final long callingId = Binder.clearCallingIdentity(); try { @@ -14382,6 +13000,7 @@ public class PackageManagerService extends IPackageManager.Stub pkgSetting.setSuspended(suspended, callingPackage, dialogMessage, appExtras, launcherExtras, userId); changedPackagesList.add(packageName); + changedUids.add(UserHandle.getUid(userId, pkgSetting.appId)); } } } finally { @@ -14390,7 +13009,8 @@ public class PackageManagerService extends IPackageManager.Stub if (!changedPackagesList.isEmpty()) { final String[] changedPackages = changedPackagesList.toArray( new String[changedPackagesList.size()]); - sendPackagesSuspendedForUser(changedPackages, userId, suspended, launcherExtras); + sendPackagesSuspendedForUser( + changedPackages, changedUids.toArray(), userId, suspended, launcherExtras); sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId); synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(userId); @@ -14505,12 +13125,14 @@ public class PackageManagerService extends IPackageManager.Stub private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) { final List<String> affectedPackages = new ArrayList<>(); + final IntArray affectedUids = new IntArray(); synchronized (mPackages) { for (PackageSetting ps : mSettings.mPackages.values()) { final PackageUserState pus = ps.readUserState(userId); if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) { ps.setSuspended(false, null, null, null, null, userId); affectedPackages.add(ps.name); + affectedUids.add(UserHandle.getUid(userId, ps.getAppId())); } } } @@ -14518,7 +13140,8 @@ public class PackageManagerService extends IPackageManager.Stub final String[] packageArray = affectedPackages.toArray( new String[affectedPackages.size()]); sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId); - sendPackagesSuspendedForUser(packageArray, userId, false, null); + sendPackagesSuspendedForUser( + packageArray, affectedUids.toArray(), userId, false, null); // Write package restrictions immediately to avoid an inconsistent state. mSettings.writePackageRestrictionsLPr(userId); } @@ -16667,13 +15290,16 @@ public class PackageManagerService extends IPackageManager.Stub final boolean oem = isOemApp(oldPackage); final boolean vendor = isVendorApp(oldPackage); final boolean product = isProductApp(oldPackage); + final boolean productServices = isProductServicesApp(oldPackage); + final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) | (vendor ? SCAN_AS_VENDOR : 0) - | (product ? SCAN_AS_PRODUCT : 0); + | (product ? SCAN_AS_PRODUCT : 0) + | (productServices ? SCAN_AS_PRODUCT_SERVICES : 0); replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags, user, allUsers, installerPackageName, res, installReason); @@ -17982,6 +16608,11 @@ public class PackageManagerService extends IPackageManager.Stub return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; } + private static boolean isProductServicesApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -18721,10 +17352,13 @@ public class PackageManagerService extends IPackageManager.Stub final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); final File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app"); final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); - return path.startsWith(privilegedAppDir.getCanonicalPath()) - || path.startsWith(privilegedVendorAppDir.getCanonicalPath()) - || path.startsWith(privilegedOdmAppDir.getCanonicalPath()) - || path.startsWith(privilegedProductAppDir.getCanonicalPath()); + final File privilegedProductServicesAppDir = + new File(Environment.getProductServicesDirectory(), "priv-app"); + return path.startsWith(privilegedAppDir.getCanonicalPath() + "/") + || path.startsWith(privilegedVendorAppDir.getCanonicalPath() + "/") + || path.startsWith(privilegedOdmAppDir.getCanonicalPath() + "/") + || path.startsWith(privilegedProductAppDir.getCanonicalPath() + "/") + || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath() + "/"); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18733,7 +17367,7 @@ public class PackageManagerService extends IPackageManager.Stub static boolean locationIsOem(String path) { try { - return path.startsWith(Environment.getOemDirectory().getCanonicalPath()); + return path.startsWith(Environment.getOemDirectory().getCanonicalPath() + "/"); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18742,8 +17376,8 @@ public class PackageManagerService extends IPackageManager.Stub static boolean locationIsVendor(String path) { try { - return path.startsWith(Environment.getVendorDirectory().getCanonicalPath()) - || path.startsWith(Environment.getOdmDirectory().getCanonicalPath()); + return path.startsWith(Environment.getVendorDirectory().getCanonicalPath() + "/") + || path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/"); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18752,7 +17386,17 @@ public class PackageManagerService extends IPackageManager.Stub static boolean locationIsProduct(String path) { try { - return path.startsWith(Environment.getProductDirectory().getCanonicalPath()); + return path.startsWith(Environment.getProductDirectory().getCanonicalPath() + "/"); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + + static boolean locationIsProductServices(String path) { + try { + return path.startsWith( + Environment.getProductServicesDirectory().getCanonicalPath() + "/"); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18886,6 +17530,9 @@ public class PackageManagerService extends IPackageManager.Stub if (locationIsProduct(codePathString)) { scanFlags |= SCAN_AS_PRODUCT; } + if (locationIsProductServices(codePathString)) { + scanFlags |= SCAN_AS_PRODUCT_SERVICES; + } final File codePath = new File(codePathString); final PackageParser.Package pkg = @@ -20078,7 +18725,7 @@ public class PackageManagerService extends IPackageManager.Stub try { synchronized (mPackages) { clearPackagePreferredActivitiesLPw(null, userId); - mSettings.applyDefaultPreferredAppsLPw(this, userId); + mSettings.applyDefaultPreferredAppsLPw(userId); // TODO: We have to reset the default SMS and Phone. This requires // significant refactoring to keep all default apps in the package // manager (cleaner but more work) or have the services provide @@ -21319,7 +19966,7 @@ public class PackageManagerService extends IPackageManager.Stub PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i); removed.clear(); for (PreferredActivity pa : pir.filterSet()) { - if (mActivities.mActivities.get(pa.mPref.mComponent) == null) { + if (!mComponentResolver.isActivityDefined(pa.mPref.mComponent)) { removed.add(pa); } } @@ -21380,15 +20027,20 @@ public class PackageManagerService extends IPackageManager.Stub mDexManager.systemReady(); mPackageDexOptimizer.systemReady(); - StorageManagerInternal StorageManagerInternal = LocalServices.getService( + StorageManagerInternal storageManagerInternal = LocalServices.getService( StorageManagerInternal.class); - StorageManagerInternal.addExternalStoragePolicy( + storageManagerInternal.addExternalStoragePolicy( new StorageManagerInternal.ExternalStorageMountPolicy() { @Override public int getMountMode(int uid, String packageName) { if (Process.isIsolated(uid)) { return Zygote.MOUNT_EXTERNAL_NONE; } + if (SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { + return checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED + ? Zygote.MOUNT_EXTERNAL_FULL + : Zygote.MOUNT_EXTERNAL_WRITE; + } if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) { return Zygote.MOUNT_EXTERNAL_DEFAULT; } @@ -21462,6 +20114,7 @@ public class PackageManagerService extends IPackageManager.Stub this, in, out, err, args, callback, resultReceiver); } + @SuppressWarnings("resource") @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; @@ -21792,32 +20445,16 @@ public class PackageManagerService extends IPackageManager.Stub } if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { - if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:" - : "Activity Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } + mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { - if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:" - : "Receiver Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } + mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { - if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:" - : "Service Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } + mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { - if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:" - : "Provider Resolver Table:", " ", packageName, - dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) { - dumpState.setTitlePrinted(true); - } + mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { @@ -21919,40 +20556,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { - boolean printedSomething = false; - for (PackageParser.Provider p : mProviders.mProviders.values()) { - if (packageName != null && !packageName.equals(p.info.packageName)) { - continue; - } - if (!printedSomething) { - if (dumpState.onTitlePrinted()) - pw.println(); - pw.println("Registered ContentProviders:"); - printedSomething = true; - } - pw.print(" "); p.printComponentShortName(pw); pw.println(":"); - pw.print(" "); pw.println(p.toString()); - } - printedSomething = false; - for (Map.Entry<String, PackageParser.Provider> entry : - mProvidersByAuthority.entrySet()) { - PackageParser.Provider p = entry.getValue(); - if (packageName != null && !packageName.equals(p.info.packageName)) { - continue; - } - if (!printedSomething) { - if (dumpState.onTitlePrinted()) - pw.println(); - pw.println("ContentProvider Authorities:"); - printedSomething = true; - } - pw.print(" ["); pw.print(entry.getKey()); pw.println("]:"); - pw.print(" "); pw.println(p.toString()); - if (p.info != null && p.info.applicationInfo != null) { - final String appInfo = p.info.applicationInfo.toString(); - pw.print(" applicationInfo="); pw.println(appInfo); - } - } + mComponentResolver.dumpContentProviders(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) { @@ -22034,21 +20638,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { - if (dumpState.onTitlePrinted()) pw.println(); - pw.println("Service permissions:"); - - final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator(); - while (filterIterator.hasNext()) { - final ServiceIntentInfo info = filterIterator.next(); - final ServiceInfo serviceInfo = info.service.info; - final String permission = serviceInfo.permission; - if (permission != null) { - pw.print(" "); - pw.print(serviceInfo.getComponentName().flattenToShortString()); - pw.print(": "); - pw.println(permission); - } - } + mComponentResolver.dumpServicePermissions(pw, dumpState, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { @@ -22179,6 +20769,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mPackages") + @SuppressWarnings("resource") private void dumpDexoptStateLPr(PrintWriter pw, String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.println(); @@ -22207,6 +20798,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mPackages") + @SuppressWarnings("resource") private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.println(); @@ -22820,6 +21412,12 @@ public class PackageManagerService extends IPackageManager.Stub } prepareAppDataContentsLeafLIF(pkg, userId, flags); + final StorageManagerInternal storageManagerInternal + = LocalServices.getService(StorageManagerInternal.class); + if (storageManagerInternal != null) { + storageManagerInternal.mountExternalStorageForApp( + pkg.packageName, appId, pkg.mSharedUserId, userId); + } } private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) { @@ -24234,6 +22832,20 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) { + synchronized (mPackages) { + return mSettings.isEnabledAndMatchLPr(info, flags, userId); + } + } + + @Override + public boolean userNeedsBadging(int userId) { + synchronized (mPackages) { + return PackageManagerService.this.userNeedsBadging(userId); + } + } + + @Override public void grantRuntimePermission(String packageName, String permName, int userId, boolean overridePolicy) { PackageManagerService.this.mPermissionManager.grantRuntimePermission( @@ -24432,7 +23044,7 @@ public class PackageManagerService extends IPackageManager.Stub public boolean canAccessComponent(int callingUid, ComponentName component, int userId) { synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); - return !PackageManagerService.this.filterAppAccessLPr( + return ps != null && !PackageManagerService.this.filterAppAccessLPr( ps, callingUid, component, TYPE_UNKNOWN, userId); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 3834a88d1c0c..f2c0395f9f0e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -25,7 +25,6 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import android.accounts.IAccountManager; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; @@ -67,7 +66,6 @@ import android.os.IBinder; import android.os.IUserManager; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.AutoCloseInputStream; -import android.os.ParcelFileDescriptor.AutoCloseOutputStream; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; @@ -84,11 +82,17 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.PrintWriterPrinter; + import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import com.android.server.SystemConfig; + import dalvik.system.DexFile; + +import libcore.io.IoUtils; +import libcore.io.Streams; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -96,10 +100,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.FileAttribute; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -110,10 +110,7 @@ import java.util.Objects; import java.util.WeakHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; -import libcore.io.IoUtils; -import libcore.io.Streams; class PackageManagerShellCommand extends ShellCommand { /** Path for streaming APK content */ @@ -1777,6 +1774,15 @@ class PackageManagerShellCommand extends ShellCommand { } } + private boolean isProductServicesApp(String pkg) { + try { + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM); + return info != null && info.applicationInfo.isProductServices(); + } catch (RemoteException e) { + return false; + } + } + private int runGetPrivappPermissions() { final String pkg = getNextArg(); if (pkg == null) { @@ -1789,6 +1795,9 @@ class PackageManagerShellCommand extends ShellCommand { privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg); } else if (isProductApp(pkg)) { privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg); + } else if (isProductServicesApp(pkg)) { + privAppPermissions = SystemConfig.getInstance() + .getProductServicesPrivAppPermissions(pkg); } else { privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); } @@ -1810,6 +1819,9 @@ class PackageManagerShellCommand extends ShellCommand { privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg); } else if (isProductApp(pkg)) { privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg); + } else if (isProductServicesApp(pkg)) { + privAppPermissions = SystemConfig.getInstance() + .getProductServicesPrivAppDenyPermissions(pkg); } else { privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index ea05b74d7443..727fb15e616a 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -148,6 +148,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; } + public boolean isProductServices() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; + } + public boolean isForwardLocked() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 7c92045c7c5e..239dc995532a 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -63,6 +63,7 @@ abstract class SettingBase { | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT + | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index e9cd7075d8e0..8dd1a0fc87fe 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -44,6 +44,7 @@ import android.content.pm.ComponentInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageCleanItem; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.PermissionInfo; @@ -88,6 +89,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; +import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.PermissionSettings; @@ -422,11 +424,8 @@ public final class Settings { /** Settings and other information about permissions */ final PermissionSettings mPermissions; - Settings(PermissionSettings permissions, Object lock) { - this(Environment.getDataDirectory(), permissions, lock); - } - - Settings(File dataDir, PermissionSettings permission, Object lock) { + Settings(File dataDir, PermissionSettings permission, + Object lock) { mLock = lock; mPermissions = permission; mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock); @@ -850,7 +849,8 @@ public final class Settings { pkgSetting.pkgPrivateFlags &= ~(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR - | ApplicationInfo.PRIVATE_FLAG_PRODUCT); + | ApplicationInfo.PRIVATE_FLAG_PRODUCT + | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES); pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; @@ -860,6 +860,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -3232,8 +3234,10 @@ public final class Settings { return true; } - void applyDefaultPreferredAppsLPw(PackageManagerService service, int userId) { + void applyDefaultPreferredAppsLPw(int userId) { // First pull data from any pre-installed apps. + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); for (PackageSetting ps : mPackages.values()) { if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null && ps.pkg.preferredActivityFilters != null) { @@ -3241,8 +3245,8 @@ public final class Settings { = ps.pkg.preferredActivityFilters; for (int i=0; i<intents.size(); i++) { PackageParser.ActivityIntentInfo aii = intents.get(i); - applyDefaultPreferredActivityLPw(service, aii, new ComponentName( - ps.name, aii.activity.className), userId); + applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName( + ps.name, aii.activity.className), userId); } } } @@ -3290,7 +3294,7 @@ public final class Settings { + " does not start with 'preferred-activities'"); continue; } - readDefaultPreferredActivitiesLPw(service, parser, userId); + readDefaultPreferredActivitiesLPw(parser, userId); } catch (XmlPullParserException e) { Slog.w(TAG, "Error reading apps file " + f, e); } catch (IOException e) { @@ -3306,8 +3310,8 @@ public final class Settings { } } - private void applyDefaultPreferredActivityLPw(PackageManagerService service, - IntentFilter tmpPa, ComponentName cn, int userId) { + private void applyDefaultPreferredActivityLPw( + PackageManagerInternal pmInternal, IntentFilter tmpPa, ComponentName cn, int userId) { // The initial preferences only specify the target activity // component and intent-filter, not the set of matches. So we // now need to query for the matches to build the correct @@ -3332,27 +3336,31 @@ public final class Settings { boolean doNonData = true; boolean hasSchemes = false; - for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) { + final int dataSchemesCount = tmpPa.countDataSchemes(); + for (int ischeme = 0; ischeme < dataSchemesCount; ischeme++) { boolean doScheme = true; - String scheme = tmpPa.getDataScheme(ischeme); + final String scheme = tmpPa.getDataScheme(ischeme); if (scheme != null && !scheme.isEmpty()) { hasSchemes = true; } - for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) { + final int dataSchemeSpecificPartsCount = tmpPa.countDataSchemeSpecificParts(); + for (int issp = 0; issp < dataSchemeSpecificPartsCount; issp++) { Uri.Builder builder = new Uri.Builder(); builder.scheme(scheme); PatternMatcher ssp = tmpPa.getDataSchemeSpecificPart(issp); builder.opaquePart(ssp.getPath()); Intent finalIntent = new Intent(intent); finalIntent.setData(builder.build()); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, scheme, ssp, null, null, userId); doScheme = false; } - for (int iauth=0; iauth<tmpPa.countDataAuthorities(); iauth++) { + final int dataAuthoritiesCount = tmpPa.countDataAuthorities(); + for (int iauth = 0; iauth < dataAuthoritiesCount; iauth++) { boolean doAuth = true; - IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(iauth); - for (int ipath=0; ipath<tmpPa.countDataPaths(); ipath++) { + final IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(iauth); + final int dataPathsCount = tmpPa.countDataPaths(); + for (int ipath = 0; ipath < dataPathsCount; ipath++) { Uri.Builder builder = new Uri.Builder(); builder.scheme(scheme); if (auth.getHost() != null) { @@ -3362,7 +3370,7 @@ public final class Settings { builder.path(path.getPath()); Intent finalIntent = new Intent(intent); finalIntent.setData(builder.build()); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, scheme, null, auth, path, userId); doAuth = doScheme = false; } @@ -3374,7 +3382,7 @@ public final class Settings { } Intent finalIntent = new Intent(intent); finalIntent.setData(builder.build()); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, scheme, null, auth, null, userId); doScheme = false; } @@ -3384,7 +3392,7 @@ public final class Settings { builder.scheme(scheme); Intent finalIntent = new Intent(intent); finalIntent.setData(builder.build()); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, scheme, null, null, null, userId); } doNonData = false; @@ -3400,129 +3408,134 @@ public final class Settings { Intent finalIntent = new Intent(intent); builder.scheme(scheme); finalIntent.setDataAndType(builder.build(), mimeType); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, scheme, null, null, null, userId); } } } else { Intent finalIntent = new Intent(intent); finalIntent.setType(mimeType); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, finalIntent, flags, cn, null, null, null, null, userId); } doNonData = false; } if (doNonData) { - applyDefaultPreferredActivityLPw(service, intent, flags, cn, + applyDefaultPreferredActivityLPw(pmInternal, intent, flags, cn, null, null, null, null, userId); } } - private void applyDefaultPreferredActivityLPw(PackageManagerService service, - Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp, + private void applyDefaultPreferredActivityLPw(PackageManagerInternal pmInternal, Intent intent, + int flags, ComponentName cn, String scheme, PatternMatcher ssp, IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) { - flags = service.updateFlagsForResolve(flags, userId, intent, Binder.getCallingUid(), false); - List<ResolveInfo> ri = service.mActivities.queryIntent(intent, - intent.getType(), flags, 0); - if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent - + " results: " + ri); + final List<ResolveInfo> ri = + pmInternal.queryIntentActivities(intent, flags, Binder.getCallingUid(), 0); + if (PackageManagerService.DEBUG_PREFERRED) { + Log.d(TAG, "Queried " + intent + " results: " + ri); + } int systemMatch = 0; int thirdPartyMatch = 0; - if (ri != null && ri.size() > 1) { - boolean haveAct = false; - ComponentName haveNonSys = null; - ComponentName[] set = new ComponentName[ri.size()]; - for (int i=0; i<ri.size(); i++) { - ActivityInfo ai = ri.get(i).activityInfo; - set[i] = new ComponentName(ai.packageName, ai.name); - if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) { - if (ri.get(i).match >= thirdPartyMatch) { - // Keep track of the best match we find of all third - // party apps, for use later to determine if we actually - // want to set a preferred app for this intent. - if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result " - + ai.packageName + "/" + ai.name + ": non-system!"); - haveNonSys = set[i]; - break; - } - } else if (cn.getPackageName().equals(ai.packageName) - && cn.getClassName().equals(ai.name)) { - if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result " - + ai.packageName + "/" + ai.name + ": default!"); - haveAct = true; - systemMatch = ri.get(i).match; - } else { - if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result " - + ai.packageName + "/" + ai.name + ": skipped"); - } - } - if (haveNonSys != null && thirdPartyMatch < systemMatch) { - // If we have a matching third party app, but its match is not as - // good as the built-in system app, then we don't want to actually - // consider it a match because presumably the built-in app is still - // the thing we want users to see by default. - haveNonSys = null; - } - if (haveAct && haveNonSys == null) { - IntentFilter filter = new IntentFilter(); - if (intent.getAction() != null) { - filter.addAction(intent.getAction()); - } - if (intent.getCategories() != null) { - for (String cat : intent.getCategories()) { - filter.addCategory(cat); + final int numMatches = (ri == null ? 0 : ri.size()); + if (numMatches <= 1) { + Slog.w(TAG, "No potential matches found for " + intent + + " while setting preferred " + cn.flattenToShortString()); + return; + } + boolean haveAct = false; + ComponentName haveNonSys = null; + ComponentName[] set = new ComponentName[ri.size()]; + for (int i = 0; i < numMatches; i++) { + final ActivityInfo ai = ri.get(i).activityInfo; + set[i] = new ComponentName(ai.packageName, ai.name); + if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + if (ri.get(i).match >= thirdPartyMatch) { + // Keep track of the best match we find of all third + // party apps, for use later to determine if we actually + // want to set a preferred app for this intent. + if (PackageManagerService.DEBUG_PREFERRED) { + Log.d(TAG, "Result " + ai.packageName + "/" + ai.name + ": non-system!"); } + haveNonSys = set[i]; + break; } - if ((flags & MATCH_DEFAULT_ONLY) != 0) { - filter.addCategory(Intent.CATEGORY_DEFAULT); - } - if (scheme != null) { - filter.addDataScheme(scheme); - } - if (ssp != null) { - filter.addDataSchemeSpecificPart(ssp.getPath(), ssp.getType()); + } else if (cn.getPackageName().equals(ai.packageName) + && cn.getClassName().equals(ai.name)) { + if (PackageManagerService.DEBUG_PREFERRED) { + Log.d(TAG, "Result " + ai.packageName + "/" + ai.name + ": default!"); } - if (auth != null) { - filter.addDataAuthority(auth); + haveAct = true; + systemMatch = ri.get(i).match; + } else { + if (PackageManagerService.DEBUG_PREFERRED) { + Log.d(TAG, "Result " + ai.packageName + "/" + ai.name + ": skipped"); } - if (path != null) { - filter.addDataPath(path); + } + } + if (haveNonSys != null && thirdPartyMatch < systemMatch) { + // If we have a matching third party app, but its match is not as + // good as the built-in system app, then we don't want to actually + // consider it a match because presumably the built-in app is still + // the thing we want users to see by default. + haveNonSys = null; + } + if (haveAct && haveNonSys == null) { + IntentFilter filter = new IntentFilter(); + if (intent.getAction() != null) { + filter.addAction(intent.getAction()); + } + if (intent.getCategories() != null) { + for (String cat : intent.getCategories()) { + filter.addCategory(cat); } - if (intent.getType() != null) { - try { - filter.addDataType(intent.getType()); - } catch (IntentFilter.MalformedMimeTypeException ex) { - Slog.w(TAG, "Malformed mimetype " + intent.getType() + " for " + cn); - } + } + if ((flags & MATCH_DEFAULT_ONLY) != 0) { + filter.addCategory(Intent.CATEGORY_DEFAULT); + } + if (scheme != null) { + filter.addDataScheme(scheme); + } + if (ssp != null) { + filter.addDataSchemeSpecificPart(ssp.getPath(), ssp.getType()); + } + if (auth != null) { + filter.addDataAuthority(auth); + } + if (path != null) { + filter.addDataPath(path); + } + if (intent.getType() != null) { + try { + filter.addDataType(intent.getType()); + } catch (IntentFilter.MalformedMimeTypeException ex) { + Slog.w(TAG, "Malformed mimetype " + intent.getType() + " for " + cn); } - PreferredActivity pa = new PreferredActivity(filter, systemMatch, set, cn, true); - editPreferredActivitiesLPw(userId).addFilter(pa); - } else if (haveNonSys == null) { - StringBuilder sb = new StringBuilder(); - sb.append("No component "); - sb.append(cn.flattenToShortString()); - sb.append(" found setting preferred "); - sb.append(intent); - sb.append("; possible matches are "); - for (int i=0; i<set.length; i++) { - if (i > 0) sb.append(", "); - sb.append(set[i].flattenToShortString()); - } - Slog.w(TAG, sb.toString()); - } else { - Slog.i(TAG, "Not setting preferred " + intent + "; found third party match " - + haveNonSys.flattenToShortString()); } + PreferredActivity pa = new PreferredActivity(filter, systemMatch, set, cn, true); + editPreferredActivitiesLPw(userId).addFilter(pa); + } else if (haveNonSys == null) { + StringBuilder sb = new StringBuilder(); + sb.append("No component "); + sb.append(cn.flattenToShortString()); + sb.append(" found setting preferred "); + sb.append(intent); + sb.append("; possible matches are "); + for (int i = 0; i < set.length; i++) { + if (i > 0) sb.append(", "); + sb.append(set[i].flattenToShortString()); + } + Slog.w(TAG, sb.toString()); } else { - Slog.w(TAG, "No potential matches found for " + intent + " while setting preferred " - + cn.flattenToShortString()); + Slog.i(TAG, "Not setting preferred " + intent + "; found third party match " + + haveNonSys.flattenToShortString()); } } - private void readDefaultPreferredActivitiesLPw(PackageManagerService service, - XmlPullParser parser, int userId) + private void readDefaultPreferredActivitiesLPw(XmlPullParser parser, int userId) throws XmlPullParserException, IOException { + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -3535,8 +3548,8 @@ public final class Settings { if (tagName.equals(TAG_ITEM)) { PreferredActivity tmpPa = new PreferredActivity(parser); if (tmpPa.mPref.getParseError() == null) { - applyDefaultPreferredActivityLPw(service, tmpPa, tmpPa.mPref.mComponent, - userId); + applyDefaultPreferredActivityLPw( + pmInternal, tmpPa, tmpPa.mPref.mComponent, userId); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <preferred-activity> " @@ -4151,7 +4164,7 @@ public final class Settings { } } synchronized (mPackages) { - applyDefaultPreferredAppsLPw(service, userHandle); + applyDefaultPreferredAppsLPw(userHandle); } } @@ -4445,6 +4458,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY", ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR", ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT", + ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", }; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 843cd8a1ba0f..5befc1f99cf3 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -25,7 +25,6 @@ import android.app.ActivityManager; import android.app.DownloadManager; import android.app.admin.DevicePolicyManager; import android.companion.CompanionDeviceManager; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -54,7 +53,6 @@ import android.provider.ContactsContract; import android.provider.MediaStore; import android.provider.Telephony.Sms.Intents; import android.security.Credentials; -import android.service.textclassifier.TextClassifierService; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; @@ -173,8 +171,11 @@ public final class DefaultPermissionGrantPolicy { @Deprecated private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>(); static { - STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); - STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + // STOPSHIP(b/112545973): remove once feature enabled by default + if (!SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)) { + STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); + STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } } private static final Set<String> MEDIA_AURAL_PERMISSIONS = new ArraySet<>(); @@ -1399,6 +1400,11 @@ public final class DefaultPermissionGrantPolicy { if (dir.isDirectory() && dir.canRead()) { Collections.addAll(ret, dir.listFiles()); } + dir = new File(Environment.getProductServicesDirectory(), + "etc/default-permissions"); + if (dir.isDirectory() && dir.canRead()) { + Collections.addAll(ret, dir.listFiles()); + } // For IoT devices, we check the oem partition for default permissions for each app. if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) { dir = new File(Environment.getOemDirectory(), "etc/default-permissions"); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 9dc0b296f97e..c4f90a125c71 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1097,6 +1097,10 @@ public class PermissionManagerService { } else if (pkg.isProduct()) { wlPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName); + } else if (pkg.isProductServices()) { + wlPermissions = + SystemConfig.getInstance().getProductServicesPrivAppPermissions( + pkg.packageName); } else { wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); } @@ -1129,6 +1133,9 @@ public class PermissionManagerService { } else if (pkg.isProduct()) { deniedPermissions = SystemConfig.getInstance() .getProductPrivAppDenyPermissions(pkg.packageName); + } else if (pkg.isProductServices()) { + deniedPermissions = SystemConfig.getInstance() + .getProductServicesPrivAppDenyPermissions(pkg.packageName); } else { deniedPermissions = SystemConfig.getInstance() .getPrivAppDenyPermissions(pkg.packageName); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f418ad4bf173..b8c9be777fef 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1053,14 +1053,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onNotificationClear(String pkg, String tag, int id, int userId, String key, - @NotificationStats.DismissalSurface int dismissalSurface, NotificationVisibility nv) { + @NotificationStats.DismissalSurface int dismissalSurface, + @NotificationStats.DismissalSentiment int dismissalSentiment, + NotificationVisibility nv) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId, - key, dismissalSurface, nv); + key, dismissalSurface, dismissalSentiment, nv); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a6bda37d6e3d..d8cbb2677f91 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -16,41 +16,7 @@ package com.android.server.wm; -import android.annotation.CallSuper; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.hardware.power.V1_0.PowerHint; -import android.os.Binder; -import android.os.Debug; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.ArraySet; -import android.util.EventLog; -import android.util.Slog; -import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; -import android.view.Display; -import android.view.DisplayInfo; -import android.view.SurfaceControl; -import android.view.WindowManager; - -import com.android.internal.util.ArrayUtils; -import com.android.server.EventLogTags; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE; @@ -60,6 +26,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.RootWindowContainerProto.DISPLAYS; +import static com.android.server.wm.RootWindowContainerProto.WINDOWS; +import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; @@ -74,19 +43,46 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS; import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; +import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; 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.H.WINDOW_FREEZE_TIMEOUT; 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; import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE; -import static com.android.server.wm.RootWindowContainerProto.DISPLAYS; -import static com.android.server.wm.RootWindowContainerProto.WINDOWS; -import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; + +import android.annotation.CallSuper; +import android.content.res.Configuration; +import android.hardware.power.V1_0.PowerHint; +import android.os.Binder; +import android.os.Debug; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.EventLog; +import android.util.Slog; +import android.util.SparseIntArray; +import android.util.proto.ProtoOutputStream; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.SurfaceControl; +import android.view.WindowManager; + +import com.android.internal.util.ArrayUtils; +import com.android.server.EventLogTags; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; /** Root {@link WindowContainer} for the device. */ class RootWindowContainer extends WindowContainer<DisplayContent> { @@ -301,6 +297,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return null; } + /** Returns the window token for the input binder if it exist in the system. */ + WindowToken getWindowToken(IBinder binder) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final DisplayContent dc = mChildren.get(i); + final WindowToken wtoken = dc.getWindowToken(binder); + if (wtoken != null) { + return wtoken; + } + } + return null; + } + /** Returns the display object the input window token is currently mapped on. */ DisplayContent getWindowTokenDisplay(WindowToken token) { if (token == null) { diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 2f189a6bcdb9..df97027da64f 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -16,20 +16,18 @@ package com.android.server.wm; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; +import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING; +import static com.android.server.wm.ScreenRotationAnimationProto.STARTED; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER; -import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING; -import static com.android.server.wm.ScreenRotationAnimationProto.STARTED; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; -import android.os.IBinder; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Display; @@ -37,7 +35,6 @@ import android.view.DisplayInfo; import android.view.Surface; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import android.view.SurfaceSession; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; @@ -268,6 +265,12 @@ class ScreenRotationAnimation { .setSecure(isSecure) .build(); + // In case display bounds change, screenshot buffer and surface may mismatch so set a + // scaling mode. + SurfaceControl.Transaction t2 = new SurfaceControl.Transaction(); + t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW); + t2.apply(true /* sync */); + // Capture a screenshot into the surface we just created. final int displayId = display.getDisplayId(); final Surface surface = new Surface(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8a571432e735..158d09a398ad 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1151,7 +1151,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalStateException("Display has not been initialialized"); } - final DisplayContent displayContent = getDisplayContentOrCreate(displayId); + final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); if (displayContent == null) { Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: " @@ -1540,9 +1540,20 @@ public class WindowManagerService extends IWindowManager.Stub * that corresponds to a display just added to DisplayManager has not yet been created. This * usually means that the call of this method was initiated from outside of Activity or Window * Manager. In most cases the regular getter should be used. + * @param displayId The preferred display Id. + * @param token The window token associated with the window we are trying to get display for. + * if not null then the display of the window token will be returned. Set to null + * is there isn't an a token associated with the request. * @see RootWindowContainer#getDisplayContent(int) */ - private DisplayContent getDisplayContentOrCreate(int displayId) { + private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) { + if (token != null) { + final WindowToken wToken = mRoot.getWindowToken(token); + if (wToken != null) { + return wToken.getDisplayContent(); + } + } + DisplayContent displayContent = mRoot.getDisplayContent(displayId); // Create an instance if possible instead of waiting for the ActivityManagerService to drive @@ -2092,12 +2103,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (focusMayChange) { - //System.out.println("Focus may change: " + win.mAttrs.getTitle()); - if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, - false /*updateInputWindows*/)) { + if (updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/)) { imMayMove = false; } - //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); } // updateFocusedWindowLocked() already assigned layers so we only need to @@ -7070,7 +7078,7 @@ public class WindowManagerService extends IWindowManager.Stub final long token = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { - final DisplayContent dc = getDisplayContentOrCreate(displayId); + final DisplayContent dc = getDisplayContentOrCreate(displayId, null); if (dc == null) { throw new IllegalArgumentException( "Trying to register a non existent display."); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c82c242ea522..2f6fca44a61e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -29,6 +29,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; +import android.hardware.display.DisplayManagerInternal; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -694,9 +695,17 @@ public final class SystemServer { // Manages Overlay packages traceBeginAndSlog("StartOverlayManagerService"); - mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer)); + OverlayManagerService overlayManagerService = new OverlayManagerService( + mSystemContext, installer); + mSystemServiceManager.startService(overlayManagerService); traceEnd(); + if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) { + // DisplayManager needs the overlay immediately. + overlayManagerService.updateSystemUiContext(); + LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged(); + } + // The sensor service needs access to package manager service, app ops // service, and permissions service, therefore we start it after them. // Start sensor service in a separate thread. Completion should be checked diff --git a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java index 91e6bd6469d8..11f2b6118e24 100644 --- a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java +++ b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java @@ -24,10 +24,17 @@ import java.nio.ByteBuffer; */ class DhcpDiscoverPacket extends DhcpPacket { /** + * The IP address of the client which sent this packet. + */ + final Inet4Address mSrcIp; + + /** * Generates a DISCOVER packet with the specified parameters. */ - DhcpDiscoverPacket(int transId, short secs, byte[] clientMac, boolean broadcast) { - super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); + DhcpDiscoverPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac, + boolean broadcast, Inet4Address srcIp) { + super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast); + mSrcIp = srcIp; } public String toString() { @@ -41,8 +48,8 @@ class DhcpDiscoverPacket extends DhcpPacket { */ public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); - fillInPacket(encap, INADDR_BROADCAST, INADDR_ANY, destUdp, - srcUdp, result, DHCP_BOOTREQUEST, mBroadcast); + fillInPacket(encap, INADDR_BROADCAST, mSrcIp, destUdp, srcUdp, result, DHCP_BOOTREQUEST, + mBroadcast); result.flip(); return result; } diff --git a/services/net/java/android/net/dhcp/DhcpLease.java b/services/net/java/android/net/dhcp/DhcpLease.java new file mode 100644 index 000000000000..d2a15b37dcc0 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpLease.java @@ -0,0 +1,138 @@ +/* + * 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.net.dhcp; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.MacAddress; +import android.os.SystemClock; +import android.text.TextUtils; + +import com.android.internal.util.HexDump; + +import java.net.Inet4Address; +import java.util.Arrays; +import java.util.Objects; + +/** + * An IPv4 address assignment done through DHCPv4. + * @hide + */ +public class DhcpLease { + public static final long EXPIRATION_NEVER = Long.MAX_VALUE; + public static final String HOSTNAME_NONE = null; + + @Nullable + private final byte[] mClientId; + @NonNull + private final MacAddress mHwAddr; + @NonNull + private final Inet4Address mNetAddr; + /** + * Expiration time for the lease, to compare with {@link SystemClock#elapsedRealtime()}. + */ + private final long mExpTime; + @Nullable + private final String mHostname; + + public DhcpLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address netAddr, long expTime, @Nullable String hostname) { + mClientId = (clientId == null ? null : Arrays.copyOf(clientId, clientId.length)); + mHwAddr = hwAddr; + mNetAddr = netAddr; + mExpTime = expTime; + mHostname = hostname; + } + + @Nullable + public byte[] getClientId() { + if (mClientId == null) { + return null; + } + return Arrays.copyOf(mClientId, mClientId.length); + } + + @NonNull + public MacAddress getHwAddr() { + return mHwAddr; + } + + @Nullable + public String getHostname() { + return mHostname; + } + + @NonNull + public Inet4Address getNetAddr() { + return mNetAddr; + } + + public long getExpTime() { + return mExpTime; + } + + /** + * Push back the expiration time of this lease. If the provided time is sooner than the original + * expiration time, the lease time will not be updated. + * + * <p>The lease hostname is updated with the provided one if set. + * @return A {@link DhcpLease} with expiration time set to max(expTime, currentExpTime) + */ + public DhcpLease renewedLease(long expTime, @Nullable String hostname) { + return new DhcpLease(mClientId, mHwAddr, mNetAddr, Math.max(expTime, mExpTime), + (hostname == null ? mHostname : hostname)); + } + + public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) { + if (mClientId != null) { + return Arrays.equals(mClientId, clientId); + } else { + return clientId == null && mHwAddr.equals(hwAddr); + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof DhcpLease)) { + return false; + } + final DhcpLease other = (DhcpLease)obj; + return Arrays.equals(mClientId, other.mClientId) + && mHwAddr.equals(other.mHwAddr) + && mNetAddr.equals(other.mNetAddr) + && mExpTime == other.mExpTime + && TextUtils.equals(mHostname, other.mHostname); + } + + @Override + public int hashCode() { + return Objects.hash(mClientId, mHwAddr, mNetAddr, mHostname, mExpTime); + } + + static String clientIdToString(byte[] bytes) { + if (bytes == null) { + return "null"; + } + return HexDump.toHexString(bytes); + } + + @Override + public String toString() { + return String.format("clientId: %s, hwAddr: %s, netAddr: %s, expTime: %d, hostname: %s", + clientIdToString(mClientId), mHwAddr.toString(), mNetAddr, mExpTime, mHostname); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java new file mode 100644 index 000000000000..7e57c9f46350 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java @@ -0,0 +1,538 @@ +/* + * 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.net.dhcp; + +import static android.net.NetworkUtils.inet4AddressToIntHTH; +import static android.net.NetworkUtils.intToInet4AddressHTH; +import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; +import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER; +import static android.net.util.NetworkConstants.IPV4_ADDR_BITS; + +import static java.lang.Math.min; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.IpPrefix; +import android.net.MacAddress; +import android.net.util.SharedLog; +import android.os.SystemClock; +import android.util.ArrayMap; + +import java.net.Inet4Address; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.Function; + +/** + * A repository managing IPv4 address assignments through DHCPv4. + * + * <p>This class is not thread-safe. All public methods should be called on a common thread or + * use some synchronization mechanism. + * + * <p>Methods are optimized for a small number of allocated leases, assuming that most of the time + * only 2~10 addresses will be allocated, which is the common case. Managing a large number of + * addresses is supported but will be slower: some operations have complexity in O(num_leases). + * @hide + */ +class DhcpLeaseRepository { + public static final byte[] CLIENTID_UNSPEC = null; + public static final Inet4Address INETADDR_UNSPEC = null; + + @NonNull + private final SharedLog mLog; + @NonNull + private final Clock mClock; + + @NonNull + private IpPrefix mPrefix; + @NonNull + private Set<Inet4Address> mReservedAddrs; + private int mSubnetAddr; + private int mSubnetMask; + private int mNumAddresses; + private long mLeaseTimeMs; + + public static class Clock { + /** + * @see SystemClock#elapsedRealtime() + */ + public long elapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + } + + /** + * Next timestamp when committed or declined leases should be checked for expired ones. This + * will always be lower than or equal to the time for the first lease to expire: it's OK not to + * update this when removing entries, but it must always be updated when adding/updating. + */ + private long mNextExpirationCheck = EXPIRATION_NEVER; + + static class DhcpLeaseException extends Exception { + DhcpLeaseException(String message) { + super(message); + } + } + + static class OutOfAddressesException extends DhcpLeaseException { + OutOfAddressesException(String message) { + super(message); + } + } + + static class InvalidAddressException extends DhcpLeaseException { + InvalidAddressException(String message) { + super(message); + } + } + + /** + * Leases by IP address + */ + private final ArrayMap<Inet4Address, DhcpLease> mCommittedLeases = new ArrayMap<>(); + + /** + * Map address -> expiration timestamp in ms. Addresses are guaranteed to be valid as defined + * by {@link #isValidAddress(Inet4Address)}, but are not necessarily otherwise available for + * assignment. + */ + private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>(); + + public DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs, + long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) { + updateParams(prefix, reservedAddrs, leaseTimeMs); + mLog = log; + mClock = clock; + } + + public void updateParams(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs, + long leaseTimeMs) { + mPrefix = prefix; + mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs)); + mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength()); + mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask; + mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength()); + mLeaseTimeMs = leaseTimeMs; + + cleanMap(mCommittedLeases); + cleanMap(mDeclinedAddrs); + } + + /** + * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as + * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address. + */ + private <T> void cleanMap(Map<Inet4Address, T> map) { + final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator(); + while (it.hasNext()) { + final Inet4Address addr = it.next().getKey(); + if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) { + it.remove(); + } + } + } + + /** + * Get a DHCP offer, to reply to a DHCPDISCOVER. Follows RFC2131 #4.3.1. + * + * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC} + * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY} + * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC} + * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE} + * @throws OutOfAddressesException The server does not have any available address + * @throws InvalidAddressException The lease was requested from an unsupported subnet + */ + @NonNull + public DhcpLease getOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address relayAddr, + @Nullable Inet4Address reqAddr, @Nullable String hostname) + throws OutOfAddressesException, InvalidAddressException { + final long currentTime = mClock.elapsedRealtime(); + final long expTime = currentTime + mLeaseTimeMs; + + removeExpiredLeases(currentTime); + + // As per #4.3.1, addresses are assigned based on the relay address if present. This + // implementation only assigns addresses if the relayAddr is inside our configured subnet. + // This also applies when the client requested a specific address for consistency between + // requests, and with older behavior. + if (isIpAddrOutsidePrefix(mPrefix, relayAddr)) { + throw new InvalidAddressException("Lease requested by relay from outside of subnet"); + } + + final DhcpLease currentLease = findByClient(clientId, hwAddr); + final DhcpLease newLease; + if (currentLease != null) { + newLease = currentLease.renewedLease(expTime, hostname); + mLog.log("Offering extended lease " + newLease); + // Do not update lease time in the map: the offer is not committed yet. + } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) { + newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname); + mLog.log("Offering requested lease " + newLease); + } else { + newLease = makeNewOffer(clientId, hwAddr, expTime, hostname); + mLog.log("Offering new generated lease " + newLease); + } + return newLease; + } + + private static boolean isIpAddrOutsidePrefix(IpPrefix prefix, Inet4Address addr) { + return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr); + } + + @Nullable + private DhcpLease findByClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) { + for (DhcpLease lease : mCommittedLeases.values()) { + if (lease.matchesClient(clientId, hwAddr)) { + return lease; + } + } + + // Note this differs from dnsmasq behavior, which would match by hwAddr if clientId was + // given but no lease keyed on clientId matched. This would prevent one interface from + // obtaining multiple leases with different clientId. + return null; + } + + /** + * Make a lease conformant to a client DHCPREQUEST or renew the client's existing lease, + * commit it to the repository and return it. + * + * <p>This method always succeeds and commits the lease if it does not throw, and has no side + * effects if it throws. + * + * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC} + * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC} + * @param sidSet Whether the server identifier was set in the request + * @return The newly created or renewed lease + * @throws InvalidAddressException The client provided an address that conflicts with its + * current configuration, or other committed/reserved leases. + */ + @NonNull + public DhcpLease requestLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address clientAddr, @Nullable Inet4Address reqAddr, boolean sidSet, + @Nullable String hostname) throws InvalidAddressException { + final long currentTime = mClock.elapsedRealtime(); + removeExpiredLeases(currentTime); + final DhcpLease assignedLease = findByClient(clientId, hwAddr); + + final Inet4Address leaseAddr = reqAddr != null ? reqAddr : clientAddr; + if (assignedLease != null) { + if (sidSet && reqAddr != null) { + // Client in SELECTING state; remove any current lease before creating a new one. + mCommittedLeases.remove(assignedLease.getNetAddr()); + } else if (!assignedLease.getNetAddr().equals(leaseAddr)) { + // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr. + // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration. + // In both cases, throw if clientAddr or reqAddr does not match the known lease. + throw new InvalidAddressException("Incorrect address for client in " + + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING")); + } + } + + // In the init-reboot case, RFC2131 #4.3.2 says that the server must not reply if + // assignedLease == null, but dnsmasq will let the client use the requested address if + // available, when configured with --dhcp-authoritative. This is preferable to avoid issues + // if the server lost the lease DB: the client would not get a reply because the server + // does not know their lease. + // Similarly in RENEWING/REBINDING state, create a lease when possible if the + // client-provided lease is unknown. + final DhcpLease lease = + checkClientAndMakeLease(clientId, hwAddr, leaseAddr, hostname, currentTime); + mLog.logf("DHCPREQUEST assignedLease %s, reqAddr=%s, sidSet=%s: created/renewed lease %s", + assignedLease, reqAddr, sidSet, lease); + return lease; + } + + /** + * Check that the client can request the specified address, make or renew the lease if yes, and + * commit it. + * + * <p>This method always succeeds and returns the lease if it does not throw, and has no + * side-effect if it throws. + * + * @return The newly created or renewed, committed lease + * @throws InvalidAddressException The client provided an address that conflicts with its + * current configuration, or other committed/reserved leases. + */ + private DhcpLease checkClientAndMakeLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address addr, @Nullable String hostname, long currentTime) + throws InvalidAddressException { + final long expTime = currentTime + mLeaseTimeMs; + final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null); + if (currentLease != null && !currentLease.matchesClient(clientId, hwAddr)) { + throw new InvalidAddressException("Address in use"); + } + + final DhcpLease lease; + if (currentLease == null) { + if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) { + lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + } else { + throw new InvalidAddressException("Lease not found and address unavailable"); + } + } else { + lease = currentLease.renewedLease(expTime, hostname); + } + commitLease(lease); + return lease; + } + + private void commitLease(@NonNull DhcpLease lease) { + mCommittedLeases.put(lease.getNetAddr(), lease); + maybeUpdateEarliestExpiration(lease.getExpTime()); + } + + /** + * Delete a committed lease from the repository. + * + * @return true if a lease matching parameters was found. + */ + public boolean releaseLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + @NonNull Inet4Address addr) { + final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null); + if (currentLease == null) { + mLog.w("Could not release unknown lease for " + addr); + return false; + } + if (currentLease.matchesClient(clientId, hwAddr)) { + mCommittedLeases.remove(addr); + mLog.log("Released lease " + currentLease); + return true; + } + mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)", + currentLease, DhcpLease.clientIdToString(clientId), hwAddr)); + return false; + } + + public void markLeaseDeclined(@NonNull Inet4Address addr) { + if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) { + mLog.logf("Not marking %s as declined: already declined or not assignable", addr); + return; + } + final long expTime = mClock.elapsedRealtime() + mLeaseTimeMs; + mDeclinedAddrs.put(addr, expTime); + mLog.logf("Marked %s as declined expiring %d", addr, expTime); + maybeUpdateEarliestExpiration(expTime); + } + + /** + * Get the list of currently valid committed leases in the repository. + */ + @NonNull + public List<DhcpLease> getCommittedLeases() { + removeExpiredLeases(mClock.elapsedRealtime()); + return new ArrayList<>(mCommittedLeases.values()); + } + + /** + * Get the set of addresses that have been marked as declined in the repository. + */ + @NonNull + public Set<Inet4Address> getDeclinedAddresses() { + removeExpiredLeases(mClock.elapsedRealtime()); + return new HashSet<>(mDeclinedAddrs.keySet()); + } + + /** + * Given the expiration time of a new committed lease or declined address, update + * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease + * to expire. + */ + private void maybeUpdateEarliestExpiration(long expTime) { + if (expTime < mNextExpirationCheck) { + mNextExpirationCheck = expTime; + } + } + + /** + * Remove expired entries from a map keyed by {@link Inet4Address}. + * + * @param tag Type of lease in the map, for logging + * @param getExpTime Functor returning the expiration time for an object in the map. + * Must not return null. + * @return The lowest expiration time among entries remaining in the map + */ + private <T> long removeExpired(long currentTime, @NonNull Map<Inet4Address, T> map, + @NonNull String tag, @NonNull Function<T, Long> getExpTime) { + final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator(); + long firstExpiration = EXPIRATION_NEVER; + while (it.hasNext()) { + final Entry<Inet4Address, T> lease = it.next(); + final long expTime = getExpTime.apply(lease.getValue()); + if (expTime <= currentTime) { + mLog.logf("Removing expired %s lease for %s (expTime=%s, currentTime=%s)", + tag, lease.getKey(), expTime, currentTime); + it.remove(); + } else { + firstExpiration = min(firstExpiration, expTime); + } + } + return firstExpiration; + } + + /** + * Go through committed and declined leases and remove the expired ones. + */ + private void removeExpiredLeases(long currentTime) { + if (currentTime < mNextExpirationCheck) { + return; + } + + final long commExp = removeExpired( + currentTime, mCommittedLeases, "committed", DhcpLease::getExpTime); + final long declExp = removeExpired( + currentTime, mDeclinedAddrs, "declined", Function.identity()); + + mNextExpirationCheck = min(commExp, declExp); + } + + private boolean isAvailable(@NonNull Inet4Address addr) { + return !mReservedAddrs.contains(addr) && !mCommittedLeases.containsKey(addr); + } + + /** + * Get the 0-based index of an address in the subnet. + * + * <p>Given ordering of addresses 5.6.7.8 < 5.6.7.9 < 5.6.8.0, the index on a subnet is defined + * so that the first address is 0, the second 1, etc. For example on a /16, 192.168.0.0 -> 0, + * 192.168.0.1 -> 1, 192.168.1.0 -> 256 + * + */ + private int getAddrIndex(int addr) { + return addr & ~mSubnetMask; + } + + private int getAddrByIndex(int index) { + return mSubnetAddr | index; + } + + /** + * Get a valid address starting from the supplied one. + * + * <p>This only checks that the address is numerically valid for assignment, not whether it is + * already in use. The return value is always inside the configured prefix, even if the supplied + * address is not. + * + * <p>If the provided address is valid, it is returned as-is. Otherwise, the next valid + * address (with the ordering in {@link #getAddrIndex(int)}) is returned. + */ + private int getValidAddress(int addr) { + final int lastByteMask = 0xff; + int addrIndex = getAddrIndex(addr); // 0-based index of the address in the subnet + + // Some OSes do not handle addresses in .255 or .0 correctly: avoid those. + final int lastByte = getAddrByIndex(addrIndex) & lastByteMask; + if (lastByte == lastByteMask) { + // Avoid .255 address, and .0 address that follows + addrIndex = (addrIndex + 2) % mNumAddresses; + } else if (lastByte == 0) { + // Avoid .0 address + addrIndex = (addrIndex + 1) % mNumAddresses; + } + + // Do not use first or last address of range + if (addrIndex == 0 || addrIndex == mNumAddresses - 1) { + // Always valid and not end of range since prefixLength is at most 30 in serving params + addrIndex = 1; + } + return getAddrByIndex(addrIndex); + } + + /** + * Returns whether the address is in the configured subnet and part of the assignable range. + */ + private boolean isValidAddress(Inet4Address addr) { + final int intAddr = inet4AddressToIntHTH(addr); + return getValidAddress(intAddr) == intAddr; + } + + private int getNextAddress(int addr) { + final int addrIndex = getAddrIndex(addr); + final int nextAddress = getAddrByIndex((addrIndex + 1) % mNumAddresses); + return getValidAddress(nextAddress); + } + + /** + * Calculate a first candidate address for a client by hashing the hardware address. + * + * <p>This will be a valid address as checked by {@link #getValidAddress(int)}, but may be + * in use. + * + * @return An IPv4 address encoded as 32-bit int + */ + private int getFirstClientAddress(MacAddress hwAddr) { + // This follows dnsmasq behavior. Advantages are: clients will often get the same + // offers for different DISCOVER even if the lease was not yet accepted or has expired, + // and address generation will generally not need to loop through many allocated addresses + // until it finds a free one. + int hash = 0; + for (byte b : hwAddr.toByteArray()) { + hash += b + (b << 8) + (b << 16); + } + // This implementation will not always result in the same IPs as dnsmasq would give out in + // Android <= P, because it includes invalid and reserved addresses in mNumAddresses while + // the configured ranges for dnsmasq did not. + final int addrIndex = hash % mNumAddresses; + return getValidAddress(getAddrByIndex(addrIndex)); + } + + /** + * Create a lease that can be offered to respond to a client DISCOVER. + * + * <p>This method always succeeds and returns the lease if it does not throw. If no non-declined + * address is available, it will try to offer the oldest declined address if valid. + * + * @throws OutOfAddressesException The server has no address left to offer + */ + private DhcpLease makeNewOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr, + long expTime, @Nullable String hostname) throws OutOfAddressesException { + int intAddr = getFirstClientAddress(hwAddr); + // Loop until a free address is found, or there are no more addresses. + // There is slightly less than this many usable addresses, but some extra looping is OK + for (int i = 0; i < mNumAddresses; i++) { + final Inet4Address addr = intToInet4AddressHTH(intAddr); + if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) { + return new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + } + intAddr = getNextAddress(intAddr); + } + + // Try freeing DECLINEd addresses if out of addresses. + final Iterator<Inet4Address> it = mDeclinedAddrs.keySet().iterator(); + while (it.hasNext()) { + final Inet4Address addr = it.next(); + it.remove(); + mLog.logf("Out of addresses in address pool: dropped declined addr %s", addr); + // isValidAddress() is always verified for entries in mDeclinedAddrs. + // However declined addresses may have been requested (typically by the machine that was + // already using the address) after being declined. + if (isAvailable(addr)) { + return new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + } + } + + throw new OutOfAddressesException("No address available for offer"); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java index 6458232b8fa0..ef9af527d063 100644 --- a/services/net/java/android/net/dhcp/DhcpNakPacket.java +++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java @@ -26,11 +26,9 @@ class DhcpNakPacket extends DhcpPacket { /** * Generates a NAK packet with the specified parameters. */ - DhcpNakPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, - Inet4Address nextIp, Inet4Address relayIp, - byte[] clientMac) { - super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, - clientMac, false); + DhcpNakPacket(int transId, short secs, Inet4Address nextIp, Inet4Address relayIp, + byte[] clientMac, boolean broadcast) { + super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, clientMac, broadcast); } public String toString() { @@ -43,11 +41,11 @@ class DhcpNakPacket extends DhcpPacket { */ public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); - Inet4Address destIp = mClientIp; - Inet4Address srcIp = mYourIp; + // Constructor does not set values for layers <= 3: use empty values + Inet4Address destIp = INADDR_ANY; + Inet4Address srcIp = INADDR_ANY; - fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, - DHCP_BOOTREPLY, mBroadcast); + fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, DHCP_BOOTREPLY, mBroadcast); result.flip(); return result; } diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index d90a4a235972..888821a8ad92 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -1,5 +1,6 @@ package android.net.dhcp; +import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; import android.net.NetworkUtils; @@ -204,6 +205,7 @@ public abstract class DhcpPacket { protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; protected static final byte DHCP_MESSAGE_TYPE_ACK = 5; protected static final byte DHCP_MESSAGE_TYPE_NAK = 6; + protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7; protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8; /** @@ -252,6 +254,7 @@ public abstract class DhcpPacket { * DHCP Optional Type: DHCP Client Identifier */ protected static final byte DHCP_CLIENT_IDENTIFIER = 61; + protected byte[] mClientId; /** * DHCP zero-length option code: pad @@ -281,7 +284,7 @@ public abstract class DhcpPacket { protected final Inet4Address mClientIp; protected final Inet4Address mYourIp; private final Inet4Address mNextIp; - private final Inet4Address mRelayIp; + protected final Inet4Address mRelayIp; /** * Does the client request a broadcast response? @@ -338,13 +341,28 @@ public abstract class DhcpPacket { return mClientMac; } + // TODO: refactor DhcpClient to set clientId when constructing packets and remove + // hasExplicitClientId logic /** - * Returns the client ID. This follows RFC 2132 and is based on the hardware address. + * Returns whether a client ID was set in the options for this packet. + */ + public boolean hasExplicitClientId() { + return mClientId != null; + } + + /** + * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID + * based on the hardware address. */ public byte[] getClientId() { - byte[] clientId = new byte[mClientMac.length + 1]; - clientId[0] = CLIENT_ID_ETHER; - System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length); + final byte[] clientId; + if (hasExplicitClientId()) { + clientId = Arrays.copyOf(mClientId, mClientId.length); + } else { + clientId = new byte[mClientMac.length + 1]; + clientId[0] = CLIENT_ID_ETHER; + System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length); + } return clientId; } @@ -531,8 +549,10 @@ public abstract class DhcpPacket { /** * Adds an optional parameter containing an array of bytes. + * + * <p>This method is a no-op if the payload argument is null. */ - protected static void addTlv(ByteBuffer buf, byte type, byte[] payload) { + protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) { if (payload != null) { if (payload.length > MAX_OPTION_LEN) { throw new IllegalArgumentException("DHCP option too long: " @@ -546,8 +566,10 @@ public abstract class DhcpPacket { /** * Adds an optional parameter containing an IP address. + * + * <p>This method is a no-op if the address argument is null. */ - protected static void addTlv(ByteBuffer buf, byte type, Inet4Address addr) { + protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) { if (addr != null) { addTlv(buf, type, addr.getAddress()); } @@ -555,8 +577,10 @@ public abstract class DhcpPacket { /** * Adds an optional parameter containing a list of IP addresses. + * + * <p>This method is a no-op if the addresses argument is null or empty. */ - protected static void addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs) { + protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) { if (addrs == null || addrs.size() == 0) return; int optionLen = 4 * addrs.size(); @@ -574,9 +598,11 @@ public abstract class DhcpPacket { } /** - * Adds an optional parameter containing a short integer + * Adds an optional parameter containing a short integer. + * + * <p>This method is a no-op if the value argument is null. */ - protected static void addTlv(ByteBuffer buf, byte type, Short value) { + protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) { if (value != null) { buf.put(type); buf.put((byte) 2); @@ -585,9 +611,11 @@ public abstract class DhcpPacket { } /** - * Adds an optional parameter containing a simple integer + * Adds an optional parameter containing a simple integer. + * + * <p>This method is a no-op if the value argument is null. */ - protected static void addTlv(ByteBuffer buf, byte type, Integer value) { + protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) { if (value != null) { buf.put(type); buf.put((byte) 4); @@ -597,12 +625,16 @@ public abstract class DhcpPacket { /** * Adds an optional parameter containing an ASCII string. + * + * <p>This method is a no-op if the string argument is null. */ - protected static void addTlv(ByteBuffer buf, byte type, String str) { - try { - addTlv(buf, type, str.getBytes("US-ASCII")); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("String is not US-ASCII: " + str); + protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) { + if (str != null) { + try { + addTlv(buf, type, str.getBytes("US-ASCII")); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("String is not US-ASCII: " + str); + } } } @@ -740,6 +772,7 @@ public abstract class DhcpPacket { Inet4Address nextIp; Inet4Address relayIp; byte[] clientMac; + byte[] clientId = null; List<Inet4Address> dnsServers = new ArrayList<>(); List<Inet4Address> gateways = new ArrayList<>(); // aka router Inet4Address serverIdentifier = null; @@ -1038,8 +1071,8 @@ public abstract class DhcpPacket { throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE, "No DHCP message type option"); case DHCP_MESSAGE_TYPE_DISCOVER: - newPacket = new DhcpDiscoverPacket( - transactionId, secs, clientMac, broadcast); + newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac, + broadcast, ipSrc); break; case DHCP_MESSAGE_TYPE_OFFER: newPacket = new DhcpOfferPacket( @@ -1047,7 +1080,7 @@ public abstract class DhcpPacket { break; case DHCP_MESSAGE_TYPE_REQUEST: newPacket = new DhcpRequestPacket( - transactionId, secs, clientIp, clientMac, broadcast); + transactionId, secs, clientIp, relayIp, clientMac, broadcast); break; case DHCP_MESSAGE_TYPE_DECLINE: newPacket = new DhcpDeclinePacket( @@ -1060,8 +1093,15 @@ public abstract class DhcpPacket { break; case DHCP_MESSAGE_TYPE_NAK: newPacket = new DhcpNakPacket( - transactionId, secs, clientIp, yourIp, nextIp, relayIp, - clientMac); + transactionId, secs, nextIp, relayIp, clientMac, broadcast); + break; + case DHCP_MESSAGE_TYPE_RELEASE: + if (serverIdentifier == null) { + throw new ParseException(DhcpErrorEvent.MISC_ERROR, + "DHCPRELEASE without server identifier"); + } + newPacket = new DhcpReleasePacket( + transactionId, serverIdentifier, clientIp, relayIp, clientMac); break; case DHCP_MESSAGE_TYPE_INFORM: newPacket = new DhcpInformPacket( @@ -1074,6 +1114,7 @@ public abstract class DhcpPacket { } newPacket.mBroadcastAddress = bcAddr; + newPacket.mClientId = clientId; newPacket.mDnsServers = dnsServers; newPacket.mDomainName = domainName; newPacket.mGateways = gateways; @@ -1173,8 +1214,8 @@ public abstract class DhcpPacket { */ public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) { - DhcpPacket pkt = new DhcpDiscoverPacket( - transactionId, secs, clientMac, broadcast); + DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, + clientMac, broadcast, INADDR_ANY /* srcIp */); pkt.mRequestedParams = expectedParams; return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); } @@ -1223,12 +1264,11 @@ public abstract class DhcpPacket { /** * Builds a DHCP-NAK packet from the required specified parameters. */ - public static ByteBuffer buildNakPacket(int encap, int transactionId, - Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) { - DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr, - serverIpAddr, serverIpAddr, serverIpAddr, mac); - pkt.mMessage = "requested address not available"; - pkt.mRequestedIp = clientIpAddr; + public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, + byte[] mac, boolean broadcast, String message) { + DhcpPacket pkt = new DhcpNakPacket( + transactionId, (short) 0, serverIpAddr, serverIpAddr, mac, broadcast); + pkt.mMessage = message; return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); } @@ -1240,7 +1280,7 @@ public abstract class DhcpPacket { byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, - clientMac, broadcast); + INADDR_ANY /* relayIp */, clientMac, broadcast); pkt.mRequestedIp = requestedIpAddress; pkt.mServerIdentifier = serverIdentifier; pkt.mHostName = hostName; diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/services/net/java/android/net/dhcp/DhcpPacketListener.java new file mode 100644 index 000000000000..498fd93fff59 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpPacketListener.java @@ -0,0 +1,84 @@ +/* + * 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.net.dhcp; + +import android.annotation.Nullable; +import android.net.util.FdEventsReader; +import android.net.util.PacketReader; +import android.os.Handler; +import android.system.Os; + +import java.io.FileDescriptor; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +/** + * A {@link FdEventsReader} to receive and parse {@link DhcpPacket}. + * @hide + */ +abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> { + static final class Payload { + final byte[] bytes = new byte[DhcpPacket.MAX_LENGTH]; + Inet4Address srcAddr; + } + + public DhcpPacketListener(Handler handler) { + super(handler, new Payload()); + } + + @Override + protected int recvBufSize(Payload buffer) { + return buffer.bytes.length; + } + + @Override + protected final void handlePacket(Payload recvbuf, int length) { + if (recvbuf.srcAddr == null) { + return; + } + + try { + final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.bytes, length, + DhcpPacket.ENCAP_BOOTP); + onReceive(packet, recvbuf.srcAddr); + } catch (DhcpPacket.ParseException e) { + logParseError(recvbuf.bytes, length, e); + } + } + + @Override + protected int readPacket(FileDescriptor fd, Payload packetBuffer) throws Exception { + final InetSocketAddress addr = new InetSocketAddress(); + final int read = Os.recvfrom( + fd, packetBuffer.bytes, 0, packetBuffer.bytes.length, 0 /* flags */, addr); + + // Buffers with null srcAddr will be dropped in handlePacket() + packetBuffer.srcAddr = inet4AddrOrNull(addr); + return read; + } + + @Nullable + private static Inet4Address inet4AddrOrNull(InetSocketAddress addr) { + return addr.getAddress() instanceof Inet4Address + ? (Inet4Address) addr.getAddress() + : null; + } + + protected abstract void onReceive(DhcpPacket packet, Inet4Address srcAddr); + protected abstract void logParseError(byte[] packet, int length, DhcpPacket.ParseException e); +} diff --git a/services/net/java/android/net/dhcp/DhcpReleasePacket.java b/services/net/java/android/net/dhcp/DhcpReleasePacket.java new file mode 100644 index 000000000000..39583032c20d --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpReleasePacket.java @@ -0,0 +1,58 @@ +/* + * 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.net.dhcp; + +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +/** + * Implements DHCP-RELEASE + */ +class DhcpReleasePacket extends DhcpPacket { + + final Inet4Address mClientAddr; + + /** + * Generates a RELEASE packet with the specified parameters. + */ + public DhcpReleasePacket(int transId, Inet4Address serverId, Inet4Address clientAddr, + Inet4Address relayIp, byte[] clientMac) { + super(transId, (short)0, clientAddr, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */, + relayIp, clientMac, false /* broadcast */); + mServerIdentifier = serverId; + mClientAddr = clientAddr; + } + + + @Override + public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) { + ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH); + fillInPacket(encap, mServerIdentifier /* destIp */, mClientIp /* srcIp */, destUdp, srcUdp, + result, DHCP_BOOTREPLY, mBroadcast); + result.flip(); + return result; + } + + @Override + void finishPacket(ByteBuffer buffer) { + addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_RELEASE); + addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId()); + addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier); + addCommonClientTlvs(buffer); + addTlvEnd(buffer); + } +} diff --git a/services/net/java/android/net/dhcp/DhcpRequestPacket.java b/services/net/java/android/net/dhcp/DhcpRequestPacket.java index 4f9aa01151ca..231d04576c28 100644 --- a/services/net/java/android/net/dhcp/DhcpRequestPacket.java +++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java @@ -28,9 +28,9 @@ class DhcpRequestPacket extends DhcpPacket { /** * Generates a REQUEST packet with the specified parameters. */ - DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, byte[] clientMac, - boolean broadcast) { - super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); + DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, Inet4Address relayIp, + byte[] clientMac, boolean broadcast) { + super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast); } public String toString() { diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java new file mode 100644 index 000000000000..ba9d116d0bd5 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpServingParams.java @@ -0,0 +1,262 @@ +/* + * 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.net.dhcp; + +import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; +import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; +import static android.net.util.NetworkConstants.IPV4_MAX_MTU; +import static android.net.util.NetworkConstants.IPV4_MIN_MTU; + +import static java.lang.Integer.toUnsignedLong; + +import android.annotation.NonNull; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.NetworkUtils; + +import java.net.Inet4Address; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Parameters used by the DhcpServer to serve requests. + * + * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate. + * @hide + */ +public class DhcpServingParams { + public static final int MTU_UNSET = 0; + public static final int MIN_PREFIX_LENGTH = 16; + public static final int MAX_PREFIX_LENGTH = 30; + + /** Server inet address and prefix to serve */ + @NonNull + public final LinkAddress serverAddr; + + /** + * Default routers to be advertised to DHCP clients. May be empty. + * This set is provided by {@link DhcpServingParams.Builder} and is immutable. + */ + @NonNull + public final Set<Inet4Address> defaultRouters; + + /** + * DNS servers to be advertised to DHCP clients. May be empty. + * This set is provided by {@link DhcpServingParams.Builder} and is immutable. + */ + @NonNull + public final Set<Inet4Address> dnsServers; + + /** + * Excluded addresses that the DHCP server is not allowed to assign to clients. + * This set is provided by {@link DhcpServingParams.Builder} and is immutable. + */ + @NonNull + public final Set<Inet4Address> excludedAddrs; + + // DHCP uses uint32. Use long for clearer code, and check range when building. + public final long dhcpLeaseTimeSecs; + public final int linkMtu; + + /** + * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are + * missing or invalid. + */ + public static class InvalidParameterException extends Exception { + public InvalidParameterException(String message) { + super(message); + } + } + + private DhcpServingParams(@NonNull LinkAddress serverAddr, + @NonNull Set<Inet4Address> defaultRouters, + @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs, + long dhcpLeaseTimeSecs, int linkMtu) { + this.serverAddr = serverAddr; + this.defaultRouters = defaultRouters; + this.dnsServers = dnsServers; + this.excludedAddrs = excludedAddrs; + this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs; + this.linkMtu = linkMtu; + } + + @NonNull + public Inet4Address getServerInet4Addr() { + return (Inet4Address) serverAddr.getAddress(); + } + + /** + * Get the served prefix mask as an IPv4 address. + * + * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0. + */ + @NonNull + public Inet4Address getPrefixMaskAsAddress() { + return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength()); + } + + /** + * Get the server broadcast address. + * + * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return + * 192.168.42.255. + */ + @NonNull + public Inet4Address getBroadcastAddress() { + return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength()); + } + + /** + * Utility class to create new instances of {@link DhcpServingParams} while checking validity + * of the parameters. + */ + public static class Builder { + private LinkAddress serverAddr; + private Set<Inet4Address> defaultRouters; + private Set<Inet4Address> dnsServers; + private Set<Inet4Address> excludedAddrs; + private long dhcpLeaseTimeSecs; + private int linkMtu = MTU_UNSET; + + /** + * Set the server address and served prefix for the DHCP server. + * + * <p>This parameter is required. + */ + public Builder setServerAddr(@NonNull LinkAddress serverAddr) { + this.serverAddr = serverAddr; + return this; + } + + /** + * Set the default routers to be advertised to DHCP clients. + * + * <p>Each router must be inside the served prefix. This may be an empty set, but it must + * always be set explicitly before building the {@link DhcpServingParams}. + */ + public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) { + this.defaultRouters = defaultRouters; + return this; + } + + /** + * Set the DNS servers to be advertised to DHCP clients. + * + * <p>This may be an empty set, but it must always be set explicitly before building the + * {@link DhcpServingParams}. + */ + public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) { + this.dnsServers = dnsServers; + return this; + } + + /** + * Set excluded addresses that the DHCP server is not allowed to assign to clients. + * + * <p>This parameter is optional. DNS servers and default routers are always excluded + * and do not need to be set here. + */ + public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) { + this.excludedAddrs = excludedAddrs; + return this; + } + + /** + * Set the lease time for leases assigned by the DHCP server. + * + * <p>This parameter is required. + */ + public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) { + this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs; + return this; + } + + /** + * Set the link MTU to be advertised to DHCP clients. + * + * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter + * is optional and defaults to {@link #MTU_UNSET}. + */ + public Builder setLinkMtu(int linkMtu) { + this.linkMtu = linkMtu; + return this; + } + + /** + * Create a new {@link DhcpServingParams} instance based on parameters set in the builder. + * + * <p>This method has no side-effects. If it does not throw, a valid + * {@link DhcpServingParams} is returned. + * @return The constructed parameters. + * @throws InvalidParameterException At least one parameter is missing or invalid. + */ + @NonNull + public DhcpServingParams build() throws InvalidParameterException { + if (serverAddr == null) { + throw new InvalidParameterException("Missing serverAddr"); + } + if (defaultRouters == null) { + throw new InvalidParameterException("Missing defaultRouters"); + } + if (dnsServers == null) { + // Empty set is OK, but enforce explicitly setting it + throw new InvalidParameterException("Missing dnsServers"); + } + if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) { + throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs); + } + if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) { + throw new InvalidParameterException("Invalid link MTU: " + linkMtu); + } + if (!serverAddr.isIPv4()) { + throw new InvalidParameterException("serverAddr must be IPv4"); + } + if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH + || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) { + throw new InvalidParameterException("Prefix length is not in supported range"); + } + + final IpPrefix prefix = makeIpPrefix(serverAddr); + for (Inet4Address addr : defaultRouters) { + if (!prefix.contains(addr)) { + throw new InvalidParameterException(String.format( + "Default router %s is not in server prefix %s", addr, serverAddr)); + } + } + + final Set<Inet4Address> excl = new HashSet<>(); + if (excludedAddrs != null) { + excl.addAll(excludedAddrs); + } + excl.add((Inet4Address) serverAddr.getAddress()); + excl.addAll(defaultRouters); + excl.addAll(dnsServers); + + return new DhcpServingParams(serverAddr, + Collections.unmodifiableSet(new HashSet<>(defaultRouters)), + Collections.unmodifiableSet(new HashSet<>(dnsServers)), + Collections.unmodifiableSet(excl), + dhcpLeaseTimeSecs, linkMtu); + } + } + + @NonNull + static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) { + return new IpPrefix(addr.getAddress(), addr.getPrefixLength()); + } +} diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index 7f821ffd369a..b77da28401d6 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -524,7 +524,7 @@ public class IpClient extends StateMachine { return false; } // There no more than one IPv4 address - if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) { + if (ipAddresses.stream().filter(LinkAddress::isIPv4).count() > 1) { return false; } diff --git a/services/net/java/android/net/util/FdEventsReader.java b/services/net/java/android/net/util/FdEventsReader.java new file mode 100644 index 000000000000..575444f89bc3 --- /dev/null +++ b/services/net/java/android/net/util/FdEventsReader.java @@ -0,0 +1,254 @@ +/* + * 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. + */ + +package android.net.util; + +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Handler; +import android.os.Looper; +import android.os.MessageQueue; +import android.system.ErrnoException; +import android.system.OsConstants; + +import libcore.io.IoUtils; + +import java.io.FileDescriptor; + + +/** + * This class encapsulates the mechanics of registering a file descriptor + * with a thread's Looper and handling read events (and errors). + * + * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override + * onStop() and onStart(). + * + * Subclasses can expect a call life-cycle like the following: + * + * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all + * goes well. Implementations may override onStart() for additional initialization. + * + * [2] yield, waiting for read event or error notification: + * + * [a] readPacket() && handlePacket() + * + * [b] if (no error): + * goto 2 + * else: + * goto 3 + * + * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never + * started). Implementations may override onStop() for additional cleanup. + * + * The packet receive buffer is recycled on every read call, so subclasses + * should make any copies they would like inside their handlePacket() + * implementation. + * + * All public methods MUST only be called from the same thread with which + * the Handler constructor argument is associated. + * + * @hide + */ +public abstract class FdEventsReader<BufferType> { + private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; + private static final int UNREGISTER_THIS_FD = 0; + + @NonNull + private final Handler mHandler; + @NonNull + private final MessageQueue mQueue; + @NonNull + private final BufferType mBuffer; + @Nullable + private FileDescriptor mFd; + private long mPacketsReceived; + + protected static void closeFd(FileDescriptor fd) { + IoUtils.closeQuietly(fd); + } + + protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) { + mHandler = h; + mQueue = mHandler.getLooper().getQueue(); + mBuffer = buffer; + } + + public final void start() { + if (onCorrectThread()) { + createAndRegisterFd(); + } else { + mHandler.post(() -> { + logError("start() called from off-thread", null); + createAndRegisterFd(); + }); + } + } + + public final void stop() { + if (onCorrectThread()) { + unregisterAndDestroyFd(); + } else { + mHandler.post(() -> { + logError("stop() called from off-thread", null); + unregisterAndDestroyFd(); + }); + } + } + + @NonNull + public Handler getHandler() { return mHandler; } + + protected abstract int recvBufSize(@NonNull BufferType buffer); + + public int recvBufSize() { return recvBufSize(mBuffer); } + + /** + * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}. + * + * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0. + */ + public final long numPacketsReceived() { return mPacketsReceived; } + + /** + * Subclasses MUST create the listening socket here, including setting + * all desired socket options, interface or address/port binding, etc. + */ + @Nullable + protected abstract FileDescriptor createFd(); + + /** + * Implementations MUST return the bytes read or throw an Exception. + * + * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or + * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer + * contents and respectively wait for further input or retry the read immediately. For all other + * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this + * method. + */ + protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer) + throws Exception; + + /** + * Called by the main loop for every packet. Any desired copies of + * |recvbuf| should be made in here, as the underlying byte array is + * reused across all reads. + */ + protected void handlePacket(@NonNull BufferType recvbuf, int length) {} + + /** + * Called by the main loop to log errors. In some cases |e| may be null. + */ + protected void logError(@NonNull String msg, @Nullable Exception e) {} + + /** + * Called by start(), if successful, just prior to returning. + */ + protected void onStart() {} + + /** + * Called by stop() just prior to returning. + */ + protected void onStop() {} + + private void createAndRegisterFd() { + if (mFd != null) return; + + try { + mFd = createFd(); + if (mFd != null) { + // Force the socket to be non-blocking. + IoUtils.setBlocking(mFd, false); + } + } catch (Exception e) { + logError("Failed to create socket: ", e); + closeFd(mFd); + mFd = null; + } + + if (mFd == null) return; + + mQueue.addOnFileDescriptorEventListener( + mFd, + FD_EVENTS, + (fd, events) -> { + // Always call handleInput() so read/recvfrom are given + // a proper chance to encounter a meaningful errno and + // perhaps log a useful error message. + if (!isRunning() || !handleInput()) { + unregisterAndDestroyFd(); + return UNREGISTER_THIS_FD; + } + return FD_EVENTS; + }); + onStart(); + } + + private boolean isRunning() { return (mFd != null) && mFd.valid(); } + + // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. + private boolean handleInput() { + while (isRunning()) { + final int bytesRead; + + try { + bytesRead = readPacket(mFd, mBuffer); + if (bytesRead < 1) { + if (isRunning()) logError("Socket closed, exiting", null); + break; + } + mPacketsReceived++; + } catch (ErrnoException e) { + if (e.errno == OsConstants.EAGAIN) { + // We've read everything there is to read this time around. + return true; + } else if (e.errno == OsConstants.EINTR) { + continue; + } else { + if (isRunning()) logError("readPacket error: ", e); + break; + } + } catch (Exception e) { + if (isRunning()) logError("readPacket error: ", e); + break; + } + + try { + handlePacket(mBuffer, bytesRead); + } catch (Exception e) { + logError("handlePacket error: ", e); + break; + } + } + + return false; + } + + private void unregisterAndDestroyFd() { + if (mFd == null) return; + + mQueue.removeOnFileDescriptorEventListener(mFd); + closeFd(mFd); + mFd = null; + onStop(); + } + + private boolean onCorrectThread() { + return (mHandler.getLooper() == Looper.myLooper()); + } +} diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java index de04fd0ced04..3defe56939f5 100644 --- a/services/net/java/android/net/util/NetworkConstants.java +++ b/services/net/java/android/net/util/NetworkConstants.java @@ -77,10 +77,12 @@ public final class NetworkConstants { /** * IPv4 constants. * - * See als: + * See also: * - https://tools.ietf.org/html/rfc791 */ public static final int IPV4_HEADER_MIN_LEN = 20; + public static final int IPV4_MIN_MTU = 68; + public static final int IPV4_MAX_MTU = 65_535; public static final int IPV4_IHL_MASK = 0xf; public static final int IPV4_FLAGS_OFFSET = 6; public static final int IPV4_FRAGMENT_MASK = 0x1fff; diff --git a/services/net/java/android/net/util/PacketReader.java b/services/net/java/android/net/util/PacketReader.java index 10da2a551e21..4aec6b6753a6 100644 --- a/services/net/java/android/net/util/PacketReader.java +++ b/services/net/java/android/net/util/PacketReader.java @@ -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. @@ -16,236 +16,46 @@ package android.net.util; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; +import static java.lang.Math.max; -import android.annotation.Nullable; import android.os.Handler; -import android.os.Looper; -import android.os.MessageQueue; -import android.os.MessageQueue.OnFileDescriptorEventListener; -import android.system.ErrnoException; import android.system.Os; -import android.system.OsConstants; - -import libcore.io.IoUtils; import java.io.FileDescriptor; -import java.io.IOException; - /** - * This class encapsulates the mechanics of registering a file descriptor - * with a thread's Looper and handling read events (and errors). - * - * Subclasses MUST implement createFd() and SHOULD override handlePacket(). - - * Subclasses can expect a call life-cycle like the following: - * - * [1] start() calls createFd() and (if all goes well) onStart() - * - * [2] yield, waiting for read event or error notification: - * - * [a] readPacket() && handlePacket() - * - * [b] if (no error): - * goto 2 - * else: - * goto 3 - * - * [3] stop() calls onStop() if not previously stopped - * - * The packet receive buffer is recycled on every read call, so subclasses - * should make any copies they would like inside their handlePacket() - * implementation. - * - * All public methods MUST only be called from the same thread with which - * the Handler constructor argument is associated. + * Specialization of {@link FdEventsReader} that reads packets into a byte array. * * TODO: rename this class to something more correctly descriptive (something * like [or less horrible than] FdReadEventsHandler?). * * @hide */ -public abstract class PacketReader { - private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; - private static final int UNREGISTER_THIS_FD = 0; +public abstract class PacketReader extends FdEventsReader<byte[]> { public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024; - private final Handler mHandler; - private final MessageQueue mQueue; - private final byte[] mPacket; - private FileDescriptor mFd; - private long mPacketsReceived; - - protected static void closeFd(FileDescriptor fd) { - IoUtils.closeQuietly(fd); - } - protected PacketReader(Handler h) { this(h, DEFAULT_RECV_BUF_SIZE); } - protected PacketReader(Handler h, int recvbufsize) { - mHandler = h; - mQueue = mHandler.getLooper().getQueue(); - mPacket = new byte[Math.max(recvbufsize, DEFAULT_RECV_BUF_SIZE)]; - } - - public final void start() { - if (onCorrectThread()) { - createAndRegisterFd(); - } else { - mHandler.post(() -> { - logError("start() called from off-thread", null); - createAndRegisterFd(); - }); - } + protected PacketReader(Handler h, int recvBufSize) { + super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]); } - public final void stop() { - if (onCorrectThread()) { - unregisterAndDestroyFd(); - } else { - mHandler.post(() -> { - logError("stop() called from off-thread", null); - unregisterAndDestroyFd(); - }); - } + @Override + protected final int recvBufSize(byte[] buffer) { + return buffer.length; } - public Handler getHandler() { return mHandler; } - - public final int recvBufSize() { return mPacket.length; } - - public final long numPacketsReceived() { return mPacketsReceived; } - - /** - * Subclasses MUST create the listening socket here, including setting - * all desired socket options, interface or address/port binding, etc. - */ - protected abstract FileDescriptor createFd(); - /** * Subclasses MAY override this to change the default read() implementation * in favour of, say, recvfrom(). * * Implementations MUST return the bytes read or throw an Exception. */ + @Override protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception { return Os.read(fd, packetBuffer, 0, packetBuffer.length); } - - /** - * Called by the main loop for every packet. Any desired copies of - * |recvbuf| should be made in here, as the underlying byte array is - * reused across all reads. - */ - protected void handlePacket(byte[] recvbuf, int length) {} - - /** - * Called by the main loop to log errors. In some cases |e| may be null. - */ - protected void logError(String msg, Exception e) {} - - /** - * Called by start(), if successful, just prior to returning. - */ - protected void onStart() {} - - /** - * Called by stop() just prior to returning. - */ - protected void onStop() {} - - private void createAndRegisterFd() { - if (mFd != null) return; - - try { - mFd = createFd(); - if (mFd != null) { - // Force the socket to be non-blocking. - IoUtils.setBlocking(mFd, false); - } - } catch (Exception e) { - logError("Failed to create socket: ", e); - closeFd(mFd); - mFd = null; - return; - } - - if (mFd == null) return; - - mQueue.addOnFileDescriptorEventListener( - mFd, - FD_EVENTS, - new OnFileDescriptorEventListener() { - @Override - public int onFileDescriptorEvents(FileDescriptor fd, int events) { - // Always call handleInput() so read/recvfrom are given - // a proper chance to encounter a meaningful errno and - // perhaps log a useful error message. - if (!isRunning() || !handleInput()) { - unregisterAndDestroyFd(); - return UNREGISTER_THIS_FD; - } - return FD_EVENTS; - } - }); - onStart(); - } - - private boolean isRunning() { return (mFd != null) && mFd.valid(); } - - // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. - private boolean handleInput() { - while (isRunning()) { - final int bytesRead; - - try { - bytesRead = readPacket(mFd, mPacket); - if (bytesRead < 1) { - if (isRunning()) logError("Socket closed, exiting", null); - break; - } - mPacketsReceived++; - } catch (ErrnoException e) { - if (e.errno == OsConstants.EAGAIN) { - // We've read everything there is to read this time around. - return true; - } else if (e.errno == OsConstants.EINTR) { - continue; - } else { - if (isRunning()) logError("readPacket error: ", e); - break; - } - } catch (Exception e) { - if (isRunning()) logError("readPacket error: ", e); - break; - } - - try { - handlePacket(mPacket, bytesRead); - } catch (Exception e) { - logError("handlePacket error: ", e); - break; - } - } - - return false; - } - - private void unregisterAndDestroyFd() { - if (mFd == null) return; - - mQueue.removeOnFileDescriptorEventListener(mFd); - closeFd(mFd); - mFd = null; - onStop(); - } - - private boolean onCorrectThread() { - return (mHandler.getLooper() == Looper.myLooper()); - } } diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java index bbd3d13efbd6..f7bf393f367b 100644 --- a/services/net/java/android/net/util/SharedLog.java +++ b/services/net/java/android/net/util/SharedLog.java @@ -16,6 +16,7 @@ package android.net.util; +import android.annotation.NonNull; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; @@ -90,6 +91,13 @@ public class SharedLog { Log.e(mTag, record(Category.ERROR, msg)); } + /** + * Log an error due to an exception, with the exception stacktrace. + */ + public void e(@NonNull String msg, @NonNull Throwable e) { + Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e); + } + public void i(String msg) { Log.i(mTag, record(Category.NONE, msg)); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java index 9d617a96e60f..48c89025e865 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java @@ -18,13 +18,13 @@ package com.android.server.hdmi; import static com.google.common.truth.Truth.assertThat; import android.annotation.Nullable; +import android.app.Instrumentation; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Looper; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -44,13 +44,16 @@ public class ArcTerminationActionFromAvrTest { private boolean mShouldDispatchReportArcTerminated; private boolean mArcEnabled; private boolean mSetArcStatusCalled; + private Instrumentation mInstrumentation; @Before public void setUp() { mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1); + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + HdmiControlService hdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(mInstrumentation.getTargetContext()) { @Override void sendCecCommand( HdmiCecMessage command, @Nullable SendMessageCallback callback) { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java index 81145103f689..3736df547b05 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java @@ -22,9 +22,8 @@ import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Looper; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import com.android.server.hdmi.HdmiCecLocalDeviceAudioSystem.TvSystemAudioModeSupportedCallback; import org.junit.Before; @@ -50,7 +49,7 @@ public class DetectTvSystemAudioModeSupportActionTest { public void SetUp() { mDeviceInfoForTests = new HdmiDeviceInfo(1001, 1234); HdmiControlService hdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override void sendCecCommand( diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java index cc005ed266b3..da840be9bca7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java @@ -18,7 +18,6 @@ package com.android.server.hdmi; import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK; import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; - import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2; @@ -26,18 +25,15 @@ import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3; import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; - import static junit.framework.Assert.assertEquals; import android.content.Context; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Looper; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -84,7 +80,7 @@ public class HdmiCecControllerTest { public void SetUp() { mMyLooper = mTestLooper.getLooper(); mMyLooper = mTestLooper.getLooper(); - mHdmiControlService = new MyHdmiControlService(null); + mHdmiControlService = new MyHdmiControlService(InstrumentationRegistry.getTargetContext()); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index 6dbbbfe8e9e4..9e3a0eaa68f6 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -30,14 +30,13 @@ import android.media.AudioManager; import android.os.Looper; import android.os.SystemProperties; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import org.junit.Before; -import org.junit.Test; import org.junit.Ignore; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -48,7 +47,10 @@ import java.util.ArrayList; /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */ public class HdmiCecLocalDeviceAudioSystemTest { - private static final String TAG = "HdmiCecLocalDeviceAudioSystemTest"; + private static final HdmiCecMessage MESSAGE_REQUEST_SAD_LCPM = + HdmiCecMessageBuilder.buildRequestShortAudioDescriptor( + ADDR_TV, ADDR_AUDIO_SYSTEM, new int[] {Constants.AUDIO_CODEC_LPCM}); + private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem; @@ -61,9 +63,9 @@ public class HdmiCecLocalDeviceAudioSystemTest { private boolean mMusicMute; @Before - public void SetUp() { + public void setUp() { mHdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override AudioManager getAudioManager() { return new AudioManager() { @@ -172,6 +174,60 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Ignore("b/80297700") @Test + public void handleRequestShortAudioDescriptor_featureDisabled() throws Exception { + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, + Constants.ABORT_REFUSED); + + mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(false); + assertThat( + mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( + MESSAGE_REQUEST_SAD_LCPM)) + .isTrue(); + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + } + + @Test + public void handleRequestShortAudioDescriptor_samOff() throws Exception { + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, + Constants.ABORT_NOT_IN_CORRECT_MODE); + + mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false); + assertThat( + mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( + MESSAGE_REQUEST_SAD_LCPM)) + .isEqualTo(true); + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + } + + @Test + public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception { + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, + Constants.ABORT_UNABLE_TO_DETERMINE); + + mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true); + assertThat( + mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor( + MESSAGE_REQUEST_SAD_LCPM)) + .isEqualTo(true); + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + } + + @Test public void handleSetSystemAudioMode_setOn_orignalOff() { mMusicMute = true; HdmiCecMessage messageSet = diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java index daf35dd382fa..910af78b2d7e 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -30,9 +30,9 @@ import static junit.framework.Assert.assertTrue; import android.hardware.hdmi.HdmiControlManager; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - +import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -95,7 +95,7 @@ public class HdmiCecLocalDeviceTest { @Before public void SetUp() { mHdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override boolean isControlEnabled() { return isControlEnabled; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 71af71e711ea..18c9a653dc7d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -25,9 +25,8 @@ import static junit.framework.Assert.assertTrue; import android.os.Looper; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -107,7 +106,7 @@ public class HdmiControlServiceTest { @Before public void SetUp() { mHdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override boolean isStandbyMessageReceived() { return mStandbyMessageReceived; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java index 6ff1c0f2cef1..d914b9a090a2 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java @@ -26,9 +26,8 @@ import android.hardware.tv.cec.V1_0.SendMessageResult; import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; - +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,7 +54,7 @@ public class SystemAudioInitiationActionFromAvrTest { public void SetUp() { mDeviceInfoForTests = new HdmiDeviceInfo(1001, 1234); HdmiControlService hdmiControlService = - new HdmiControlService(null) { + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override void sendCecCommand( diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index e379cd09f0f8..111fb7488d89 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -107,4 +107,24 @@ public class PackageManagerServiceTest { // TODO: test that sendApplicationHiddenForUser() actually fills in // broadcastUsers } + + @Test + public void testPartitions() throws Exception { + String[] partitions = { "system", "vendor", "odm", "oem", "product", "product_services" }; + String[] appdir = { "app", "priv-app" }; + for (int i = 0; i < partitions.length; i++) { + for (int j = 0; j < appdir.length; j++) { + String canonical = new File("/" + partitions[i]).getCanonicalPath(); + String path = String.format("%s/%s/A.apk", canonical, appdir[j]); + + Assert.assertEquals(j == 1 && i != 3, + PackageManagerService.locationIsPrivileged(path)); + + Assert.assertEquals(i == 1 || i == 2, PackageManagerService.locationIsVendor(path)); + Assert.assertEquals(i == 3, PackageManagerService.locationIsOem(path)); + Assert.assertEquals(i == 4, PackageManagerService.locationIsProduct(path)); + Assert.assertEquals(i == 5, PackageManagerService.locationIsProductServices(path)); + } + } + } } 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 4dcb8cf8b327..0ff124e4ce7a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2483,13 +2483,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(), - r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, nv); + r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, + NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv); waitForIdle(); assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); } @Test + public void testStats_dismissalSentiment() throws Exception { + final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(r); + + final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); + mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(), + r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, + NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv); + waitForIdle(); + + assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE, + r.getStats().getDismissalSentiment()); + } + + @Test public void testApplyAdjustmentMultiUser() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java index 0a630f462949..bae8564a0694 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java @@ -16,6 +16,8 @@ package com.android.server.notification; import static android.service.notification.NotificationStats.DISMISSAL_PEEK; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEGATIVE; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_POSITIVE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -46,6 +48,7 @@ public class NotificationStatsTest extends UiServiceTestCase { assertFalse(stats.hasViewedSettings()); assertFalse(stats.hasSnoozed()); assertEquals(NotificationStats.DISMISSAL_NOT_DISMISSED, stats.getDismissalSurface()); + assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN, stats.getDismissalSentiment()); } @Test @@ -97,10 +100,19 @@ public class NotificationStatsTest extends UiServiceTestCase { } @Test + public void testDismissalSentiment() { + NotificationStats stats = new NotificationStats(); + stats.setDismissalSentiment(DISMISS_SENTIMENT_NEGATIVE); + assertEquals(DISMISS_SENTIMENT_NEGATIVE, stats.getDismissalSentiment()); + assertFalse(stats.hasInteracted()); + } + + @Test public void testWriteToParcel() { NotificationStats stats = new NotificationStats(); stats.setViewedSettings(); stats.setDismissalSurface(NotificationStats.DISMISSAL_AOD); + stats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_POSITIVE); Parcel parcel = Parcel.obtain(); stats.writeToParcel(parcel, 0); parcel.setDataPosition(0); diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index 61d6b7def981..d12eda75ff32 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -155,8 +155,6 @@ public class StorageStatsService extends IStorageStatsManager.Stub { @Override public boolean isQuotaSupported(String volumeUuid, String callingPackage) { - enforcePermission(Binder.getCallingUid(), callingPackage); - try { return mInstaller.isQuotaSupported(volumeUuid); } catch (InstallerException e) { @@ -166,8 +164,6 @@ public class StorageStatsService extends IStorageStatsManager.Stub { @Override public boolean isReservedSupported(String volumeUuid, String callingPackage) { - enforcePermission(Binder.getCallingUid(), callingPackage); - if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) { return SystemProperties.getBoolean(StorageManager.PROP_HAS_RESERVED, false); } else { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index a45d70bb5d78..97068a6c844a 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -163,10 +163,20 @@ public class CarrierConfigManager { /** * Flag indicating whether radio is to be restarted on error PDP_FAIL_REGULAR_DEACTIVATION * This is false by default. + * + * @deprecated Use {@link #KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY} instead */ - public static final String - KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = - "restart_radio_on_pdp_fail_regular_deactivation_bool"; + @Deprecated + public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = + "restart_radio_on_pdp_fail_regular_deactivation_bool"; + + /** + * A list of failure cause codes that will trigger a modem restart when telephony receiving + * one of those during data setup. The cause codes are defined in 3GPP TS 24.008 Annex I and + * TS 24.301 Annex B. + */ + public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = + "radio_restart_failure_causes_int_array"; /** * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity. @@ -2124,6 +2134,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false); sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true); sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false); + sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[]{}); sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0); sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, ""); sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, ""); diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index c240dbb684e6..76a002681710 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -129,6 +129,12 @@ public abstract class CellIdentity implements Parcelable { return mAlphaShort; } + /** + * @return a CellLocation object for this CellIdentity + * @hide + */ + public abstract CellLocation asCellLocation(); + @Override public boolean equals(Object other) { if (!(other instanceof CellIdentity)) { diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 5b67dc44fe3c..9218bdc31fa8 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -19,7 +19,7 @@ package android.telephony; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; -import android.text.TextUtils; +import android.telephony.cdma.CdmaCellLocation; import java.util.Objects; @@ -178,6 +178,18 @@ public final class CellIdentityCdma extends CellIdentity { super.hashCode()); } + /** @hide */ + @Override + public CdmaCellLocation asCellLocation() { + CdmaCellLocation cl = new CdmaCellLocation(); + int bsid = mBasestationId != Integer.MAX_VALUE ? mBasestationId : -1; + int sid = mSystemId != Integer.MAX_VALUE ? mSystemId : -1; + int nid = mNetworkId != Integer.MAX_VALUE ? mNetworkId : -1; + // lat and long already use Integer.MAX_VALUE for invalid/unknown + cl.setCellLocationData(bsid, mLatitude, mLongitude, sid, nid); + return cl; + } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 5c847914b57b..cb9dbf369d7e 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -19,6 +19,7 @@ package android.telephony; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import java.util.Objects; @@ -198,6 +199,17 @@ public final class CellIdentityGsm extends CellIdentity { return Integer.MAX_VALUE; } + /** @hide */ + @Override + public GsmCellLocation asCellLocation() { + GsmCellLocation cl = new GsmCellLocation(); + int lac = mLac != Integer.MAX_VALUE ? mLac : -1; + int cid = mCid != Integer.MAX_VALUE ? mCid : -1; + cl.setLacAndCid(lac, cid); + cl.setPsc(-1); + return cl; + } + @Override public int hashCode() { return Objects.hash(mLac, mCid, super.hashCode()); diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 65c904b8548b..b44e891fa870 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -19,6 +19,7 @@ package android.telephony; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import java.util.Objects; @@ -200,6 +201,28 @@ public final class CellIdentityLte extends CellIdentity { return mEarfcn; } + /** + * A hack to allow tunneling of LTE information via GsmCellLocation + * so that older Network Location Providers can return some information + * on LTE only networks, see bug 9228974. + * + * The tunnel'd LTE information is returned as follows: + * LAC = TAC field + * CID = CI field + * PSC = 0. + * + * @hide + */ + @Override + public GsmCellLocation asCellLocation() { + GsmCellLocation cl = new GsmCellLocation(); + int tac = mTac != Integer.MAX_VALUE ? mTac : -1; + int cid = mCi != Integer.MAX_VALUE ? mCi : -1; + cl.setLacAndCid(tac, cid); + cl.setPsc(0); + return cl; + } + @Override public int hashCode() { return Objects.hash(mCi, mPci, mTac, super.hashCode()); diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 21b9601bcad9..5a9e474806a3 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -17,6 +17,7 @@ package android.telephony; import android.os.Parcel; +import android.telephony.gsm.GsmCellLocation; import java.util.Objects; @@ -134,6 +135,17 @@ public final class CellIdentityTdscdma extends CellIdentity { return mUarfcn; } + /** @hide */ + @Override + public GsmCellLocation asCellLocation() { + GsmCellLocation cl = new GsmCellLocation(); + int lac = mLac != Integer.MAX_VALUE ? mLac : -1; + int cid = mCid != Integer.MAX_VALUE ? mCid : -1; + cl.setLacAndCid(lac, cid); + cl.setPsc(-1); // There is no PSC for TD-SCDMA; not using this for CPI to stem shenanigans + return cl; + } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index e26fcb314afa..727d9908b9b1 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -19,6 +19,7 @@ package android.telephony; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import java.util.Objects; @@ -191,6 +192,19 @@ public final class CellIdentityWcdma extends CellIdentity { return mUarfcn; } + /** @hide */ + @Override + public GsmCellLocation asCellLocation() { + GsmCellLocation cl = new GsmCellLocation(); + int lac = mLac != Integer.MAX_VALUE ? mLac : -1; + int cid = mCid != Integer.MAX_VALUE ? mCid : -1; + int psc = mPsc != Integer.MAX_VALUE ? mPsc : -1; + cl.setLacAndCid(lac, cid); + cl.setPsc(psc); + + return cl; + } + @Override public boolean equals(Object other) { if (this == other) { diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 9565507f4505..ea408bf8ff59 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -274,6 +274,17 @@ public final class SmsManager { private static final int SMS_PICK = 2; /** + * 3gpp2 SMS priority is not specified + * @hide + */ + public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1; + /** + * 3gpp SMS period is not specified + * @hide + */ + public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; + + /** * Send a text based SMS. * * <p class="note"><strong>Note:</strong> Using this method requires that your app has the @@ -464,11 +475,11 @@ public final class SmsManager { } if (priority < 0x00 || priority > 0x03) { - throw new IllegalArgumentException("Invalid priority"); + priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; } if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { - throw new IllegalArgumentException("Invalid validity period"); + validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; } try { @@ -728,7 +739,8 @@ public final class SmsManager { ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod) { sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, - deliveryIntents, true /* persistMessage*/); + deliveryIntents, true /* persistMessage*/, priority, expectMore, + validityPeriod); } private void sendMultipartTextMessageInternal( @@ -743,11 +755,11 @@ public final class SmsManager { } if (priority < 0x00 || priority > 0x03) { - throw new IllegalArgumentException("Invalid priority"); + priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; } if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { - throw new IllegalArgumentException("Invalid validity period"); + validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; } if (parts.size() > 1) { diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl new file mode 100644 index 000000000000..9c80cb77e435 --- /dev/null +++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl @@ -0,0 +1,28 @@ +/* + * 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.telephony.data; + +import android.telephony.data.IQualifiedNetworksServiceCallback; + +/** + * {@hide} + */ +interface IQualifiedNetworksService +{ + oneway void createNetworkAvailabilityUpdater(int slotId, IQualifiedNetworksServiceCallback callback); + oneway void removeNetworkAvailabilityUpdater(int slotId); +} diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl new file mode 100644 index 000000000000..e8e1f017789f --- /dev/null +++ b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl @@ -0,0 +1,26 @@ +/* + * 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.telephony.data; + +/** + * The qualified networks service call back interface + * @hide + */ +oneway interface IQualifiedNetworksServiceCallback +{ + void onQualifiedNetworkTypesChanged(int apnType, in int[] qualifiedNetworkTypesList); +} diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java new file mode 100644 index 000000000000..bb89f193e03a --- /dev/null +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -0,0 +1,286 @@ +/* + * 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.telephony.data; + +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.Rlog; +import android.telephony.data.ApnSetting.ApnType; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Base class of the qualified networks service. Services that extend QualifiedNetworksService must + * register the service in their AndroidManifest to be detected by the framework. They must be + * protected by the permission "android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE". + * The qualified networks service definition in the manifest must follow the following format: + * ... + * <service android:name=".xxxQualifiedNetworksService" + * android:permission="android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE" > + * <intent-filter> + * <action android:name="android.telephony.data.QualifiedNetworksService" /> + * </intent-filter> + * </service> + * @hide + */ +@SystemApi +public abstract class QualifiedNetworksService extends Service { + private static final String TAG = QualifiedNetworksService.class.getSimpleName(); + + public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = + "android.telephony.data.QualifiedNetworksService"; + + private static final int QNS_CREATE_NETWORK_AVAILABILITY_UPDATER = 1; + private static final int QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER = 2; + private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS = 3; + private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4; + + private final HandlerThread mHandlerThread; + + private final QualifiedNetworksServiceHandler mHandler; + + private final SparseArray<NetworkAvailabilityUpdater> mUpdaters = new SparseArray<>(); + + /** @hide */ + @VisibleForTesting + public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper(); + + /** + * The abstract class of the network availability updater implementation. The vendor qualified + * network service must extend this class to report the available networks for data + * connection setup. Note that each instance of network availability updater is associated with + * one physical SIM slot. + */ + public abstract class NetworkAvailabilityUpdater implements AutoCloseable { + private final int mSlotIndex; + + private IQualifiedNetworksServiceCallback mCallback; + + /** + * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array + * of available networks. + */ + private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>(); + + /** + * Constructor + * @param slotIndex SIM slot index the network availability updater associated with. + */ + public NetworkAvailabilityUpdater(int slotIndex) { + mSlotIndex = slotIndex; + } + + /** + * @return SIM slot index the network availability updater associated with. + */ + public final int getSlotIndex() { + return mSlotIndex; + } + + private void registerForQualifiedNetworkTypesChanged( + IQualifiedNetworksServiceCallback callback) { + mCallback = callback; + + // Force sending the qualified networks upon registered. + if (mCallback != null) { + for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) { + try { + mCallback.onQualifiedNetworkTypesChanged( + mQualifiedNetworkTypesList.keyAt(i), + mQualifiedNetworkTypesList.valueAt(i)); + } catch (RemoteException e) { + loge("Failed to call onQualifiedNetworksChanged. " + e); + } + } + } + } + + /** + * Update the qualified networks list. Network availability updater must invoke this method + * whenever the qualified networks changes. If this method is never invoked for certain + * APN type, then frameworks will always use the default (i.e. cellular) data and network + * service. + * + * @param apnType APN type of the qualified networks + * @param qualifiedNetworkTypes List of network types which are qualified for data + * connection setup for {@link @apnType} in the preferred order. Each element in the array + * is a {@link AccessNetworkType}. An empty list or null indicates no networks are qualified + * for data setup. + */ + public final void updateQualifiedNetworkTypes(@ApnType int apnType, + int[] qualifiedNetworkTypes) { + mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnType, + qualifiedNetworkTypes).sendToTarget(); + } + + private void onUpdateQualifiedNetworkTypes(@ApnType int apnType, + int[] qualifiedNetworkTypes) { + mQualifiedNetworkTypesList.put(apnType, qualifiedNetworkTypes); + if (mCallback != null) { + try { + mCallback.onQualifiedNetworkTypesChanged(apnType, qualifiedNetworkTypes); + } catch (RemoteException e) { + loge("Failed to call onQualifiedNetworksChanged. " + e); + } + } + } + + /** + * Called when the qualified networks updater is removed. The extended class should + * implement this method to perform clean up works. + */ + @Override + public abstract void close(); + } + + private class QualifiedNetworksServiceHandler extends Handler { + QualifiedNetworksServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + IQualifiedNetworksServiceCallback callback; + final int slotIndex = message.arg1; + NetworkAvailabilityUpdater updater = mUpdaters.get(slotIndex); + + switch (message.what) { + case QNS_CREATE_NETWORK_AVAILABILITY_UPDATER: + if (mUpdaters.get(slotIndex) != null) { + loge("Network availability updater for slot " + slotIndex + + " already existed."); + return; + } + + updater = createNetworkAvailabilityUpdater(slotIndex); + if (updater != null) { + mUpdaters.put(slotIndex, updater); + + callback = (IQualifiedNetworksServiceCallback) message.obj; + updater.registerForQualifiedNetworkTypesChanged(callback); + } else { + loge("Failed to create network availability updater. slot index = " + + slotIndex); + } + break; + + case QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER: + if (updater != null) { + updater.close(); + mUpdaters.remove(slotIndex); + } + break; + + case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS: + for (int i = 0; i < mUpdaters.size(); i++) { + updater = mUpdaters.get(i); + if (updater != null) { + updater.close(); + } + } + mUpdaters.clear(); + break; + + case QNS_UPDATE_QUALIFIED_NETWORKS: + if (updater == null) break; + updater.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj); + break; + } + } + } + + /** + * Default constructor. + */ + public QualifiedNetworksService() { + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + + mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper()); + log("Qualified networks service created"); + } + + /** + * Create the instance of {@link NetworkAvailabilityUpdater}. Vendor qualified network service + * must override this method to facilitate the creation of {@link NetworkAvailabilityUpdater} + * instances. The system will call this method after binding the qualified networks service for + * each active SIM slot index. + * + * @param slotIndex SIM slot index the qualified networks service associated with. + * @return Qualified networks service instance + */ + public abstract NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int slotIndex); + + /** @hide */ + @Override + public IBinder onBind(Intent intent) { + if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) { + loge("Unexpected intent " + intent); + return null; + } + return mBinder; + } + + /** @hide */ + @Override + public boolean onUnbind(Intent intent) { + mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS).sendToTarget(); + return false; + } + + /** @hide */ + @Override + public void onDestroy() { + mHandlerThread.quit(); + } + + /** + * A wrapper around IQualifiedNetworksService that forwards calls to implementations of + * {@link QualifiedNetworksService}. + */ + private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub { + @Override + public void createNetworkAvailabilityUpdater(int slotIndex, + IQualifiedNetworksServiceCallback callback) { + mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0, + callback).sendToTarget(); + } + + @Override + public void removeNetworkAvailabilityUpdater(int slotIndex) { + mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0) + .sendToTarget(); + } + } + + private void log(String s) { + Rlog.d(TAG, s); + } + + private void loge(String s) { + Rlog.e(TAG, s); + } +} diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk index eb3862390338..f4250c8b4e97 100644 --- a/tests/libs-permissions/Android.mk +++ b/tests/libs-permissions/Android.mk @@ -13,3 +13,17 @@ LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product_services +LOCAL_PRODUCT_SERVICES_MODULE := true +LOCAL_SRC_FILES := $(call all-java-files-under, product_services/java) +LOCAL_REQUIRED_MODULES := com.android.test.libs.product_services.xml +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product_services.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/permissions +LOCAL_SRC_FILES:= product_services/com.android.test.libs.product_services.xml +include $(BUILD_PREBUILT) diff --git a/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml b/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml new file mode 100644 index 000000000000..082a9be80779 --- /dev/null +++ b/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<permissions> + <library name="com.android.test.libs.product_services" + file="/product_services/framework/com.android.test.libs.product_services.jar" /> +</permissions> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl b/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java index f9450adcdf30..dcbdae809889 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl +++ b/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 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. @@ -14,6 +14,16 @@ * limitations under the License. */ -package com.android.systemui.shared.system; +package com.android.test.libs.product_services; -parcelable GraphicBufferCompat;
\ No newline at end of file +/** + * Test class for product_services libs. + */ +public class LibsProductServicesTest { + + /** + * Dummy method for testing. + */ + public static void test() { + } +} diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java index 2b172dac4865..3452819835f5 100644 --- a/tests/net/java/android/net/NetworkUtilsTest.java +++ b/tests/net/java/android/net/NetworkUtilsTest.java @@ -24,6 +24,8 @@ import static android.net.NetworkUtils.intToInet4AddressHTL; import static android.net.NetworkUtils.netmaskToPrefixLength; import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL; +import static android.net.NetworkUtils.getBroadcastAddress; +import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; import static junit.framework.Assert.assertEquals; @@ -125,7 +127,6 @@ public class NetworkUtilsTest { assertInvalidNetworkMask(IPv4Address("255.255.0.255")); } - @Test public void testPrefixLengthToV4NetmaskIntHTL() { assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); @@ -266,4 +267,44 @@ public class NetworkUtilsTest { assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536), NetworkUtils.routedIPv6AddressCount(set)); } + + @Test + public void testGetPrefixMaskAsAddress() { + assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); + assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); + assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); + assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_PrefixTooLarge() { + getPrefixMaskAsInet4Address(33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_NegativePrefix() { + getPrefixMaskAsInet4Address(-1); + } + + @Test + public void testGetBroadcastAddress() { + assertEquals("192.168.15.255", + getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress()); + assertEquals("192.255.255.255", + getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress()); + assertEquals("192.168.0.123", + getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress()); + assertEquals("255.255.255.255", + getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_PrefixTooLarge() { + getBroadcastAddress(IPv4Address("192.168.0.123"), 33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_NegativePrefix() { + getBroadcastAddress(IPv4Address("192.168.0.123"), -1); + } } diff --git a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java new file mode 100644 index 000000000000..edadd6ead667 --- /dev/null +++ b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java @@ -0,0 +1,519 @@ +/* + * 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.net.dhcp; + +import static android.net.dhcp.DhcpLease.HOSTNAME_NONE; +import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC; +import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; + +import static java.lang.String.format; +import static java.net.InetAddress.parseNumericAddress; + +import android.annotation.NonNull; +import android.net.IpPrefix; +import android.net.MacAddress; +import android.net.dhcp.DhcpLeaseRepository.Clock; +import android.net.util.SharedLog; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.net.Inet4Address; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DhcpLeaseRepositoryTest { + private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY; + private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247"); + private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241"); + private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243"); + private static final MacAddress TEST_MAC_1 = MacAddress.fromBytes( + new byte[] { 5, 4, 3, 2, 1, 0 }); + private static final MacAddress TEST_MAC_2 = MacAddress.fromBytes( + new byte[] { 0, 1, 2, 3, 4, 5 }); + private static final MacAddress TEST_MAC_3 = MacAddress.fromBytes( + new byte[] { 0, 1, 2, 3, 4, 6 }); + private static final Inet4Address TEST_INETADDR_1 = parseAddr4("192.168.42.248"); + private static final Inet4Address TEST_INETADDR_2 = parseAddr4("192.168.42.249"); + private static final String TEST_HOSTNAME_1 = "hostname1"; + private static final String TEST_HOSTNAME_2 = "hostname2"; + private static final IpPrefix TEST_IP_PREFIX = new IpPrefix(TEST_SERVER_ADDR, 22); + private static final long TEST_TIME = 100L; + private static final int TEST_LEASE_TIME_MS = 3_600_000; + private static final Set<Inet4Address> TEST_EXCL_SET = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + TEST_SERVER_ADDR, TEST_DEF_ROUTER, TEST_RESERVED_ADDR))); + + @NonNull + private SharedLog mLog; + @NonNull @Mock + private Clock mClock; + @NonNull + private DhcpLeaseRepository mRepo; + + private static Inet4Address parseAddr4(String inet4Addr) { + return (Inet4Address) parseNumericAddress(inet4Addr); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mLog = new SharedLog("DhcpLeaseRepositoryTest"); + when(mClock.elapsedRealtime()).thenReturn(TEST_TIME); + mRepo = new DhcpLeaseRepository( + TEST_IP_PREFIX, TEST_EXCL_SET, TEST_LEASE_TIME_MS, mLog, mClock); + } + + /** + * Request a number of addresses through offer/request. Useful to test address exhaustion. + * @param nAddr Number of addresses to request. + */ + private void requestAddresses(byte nAddr) throws Exception { + final HashSet<Inet4Address> addrs = new HashSet<>(); + byte[] hwAddrBytes = new byte[] { 8, 4, 3, 2, 1, 0 }; + for (byte i = 0; i < nAddr; i++) { + hwAddrBytes[5] = i; + MacAddress newMac = MacAddress.fromBytes(hwAddrBytes); + final String hostname = "host_" + i; + final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname); + + assertNotNull(lease); + assertEquals(newMac, lease.getHwAddr()); + assertEquals(hostname, lease.getHostname()); + assertTrue(format("Duplicate address allocated: %s in %s", lease.getNetAddr(), addrs), + addrs.add(lease.getNetAddr())); + + mRepo.requestLease(null, newMac, null, lease.getNetAddr(), true, hostname); + } + } + + @Test + public void testAddressExhaustion() throws Exception { + // Use a /28 to quickly run out of addresses + mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS); + + // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses + requestAddresses((byte)11); + + try { + mRepo.getOffer(null, TEST_MAC_2, + null /* relayAddr */, null /* reqAddr */, HOSTNAME_NONE); + fail("Should be out of addresses"); + } catch (DhcpLeaseRepository.OutOfAddressesException e) { + // Expected + } + } + + @Test + public void testUpdateParams_LeaseCleanup() throws Exception { + // Inside /28: + final Inet4Address reqAddrIn28 = parseAddr4("192.168.42.242"); + final Inet4Address declinedAddrIn28 = parseAddr4("192.168.42.245"); + + // Inside /28, but not available there (first address of the range) + final Inet4Address declinedFirstAddrIn28 = parseAddr4("192.168.42.240"); + + final DhcpLease reqAddrIn28Lease = mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, reqAddrIn28, false, HOSTNAME_NONE); + mRepo.markLeaseDeclined(declinedAddrIn28); + mRepo.markLeaseDeclined(declinedFirstAddrIn28); + + // Inside /22, but outside /28: + final Inet4Address reqAddrIn22 = parseAddr4("192.168.42.3"); + final Inet4Address declinedAddrIn22 = parseAddr4("192.168.42.4"); + + final DhcpLease reqAddrIn22Lease = mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY, reqAddrIn22, false, HOSTNAME_NONE); + mRepo.markLeaseDeclined(declinedAddrIn22); + + // Address that will be reserved in the updateParams call below + final Inet4Address reservedAddr = parseAddr4("192.168.42.244"); + final DhcpLease reservedAddrLease = mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, reservedAddr, false, HOSTNAME_NONE); + + // Update from /22 to /28 and add another reserved address + Set<Inet4Address> newReserved = new HashSet<>(TEST_EXCL_SET); + newReserved.add(reservedAddr); + mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), newReserved, TEST_LEASE_TIME_MS); + + assertHasLease(reqAddrIn28Lease); + assertDeclined(declinedAddrIn28); + + assertNotDeclined(declinedFirstAddrIn28); + + assertNoLease(reqAddrIn22Lease); + assertNotDeclined(declinedAddrIn22); + + assertNoLease(reservedAddrLease); + } + + @Test + public void testGetOffer_StableAddress() throws Exception { + for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) { + final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + + // Same lease is offered twice + final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + assertEquals(lease, newLease); + } + } + + @Test + public void testUpdateParams_UsesNewPrefix() throws Exception { + final IpPrefix newPrefix = new IpPrefix(parseAddr4("192.168.123.0"), 24); + mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS); + + DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + INETADDR_UNSPEC, INETADDR_UNSPEC, HOSTNAME_NONE); + assertTrue(newPrefix.contains(lease.getNetAddr())); + } + + @Test + public void testGetOffer_ExistingLease() throws Exception { + mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, TEST_INETADDR_1, false, TEST_HOSTNAME_1); + + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + INETADDR_UNSPEC, INETADDR_UNSPEC, HOSTNAME_NONE); + assertEquals(TEST_INETADDR_1, offer.getNetAddr()); + assertEquals(TEST_HOSTNAME_1, offer.getHostname()); + } + + @Test + public void testGetOffer_ClientIdHasExistingLease() throws Exception { + final byte[] clientId = new byte[] { 1, 2 }; + mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY, TEST_INETADDR_1, false, + TEST_HOSTNAME_1); + + // Different MAC, but same clientId + DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2, + INETADDR_UNSPEC, INETADDR_UNSPEC, HOSTNAME_NONE); + assertEquals(TEST_INETADDR_1, offer.getNetAddr()); + assertEquals(TEST_HOSTNAME_1, offer.getHostname()); + } + + @Test + public void testGetOffer_DifferentClientId() throws Exception { + final byte[] clientId1 = new byte[] { 1, 2 }; + final byte[] clientId2 = new byte[] { 3, 4 }; + mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY, TEST_INETADDR_1, false, + TEST_HOSTNAME_1); + + // Same MAC, different client ID + DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1, + INETADDR_UNSPEC, INETADDR_UNSPEC, HOSTNAME_NONE); + // Obtains a different address + assertNotEquals(TEST_INETADDR_1, offer.getNetAddr()); + assertEquals(HOSTNAME_NONE, offer.getHostname()); + assertEquals(TEST_MAC_1, offer.getHwAddr()); + } + + @Test + public void testGetOffer_RequestedAddress() throws Exception { + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, TEST_HOSTNAME_1); + assertEquals(TEST_INETADDR_1, offer.getNetAddr()); + assertEquals(TEST_HOSTNAME_1, offer.getHostname()); + } + + @Test + public void testGetOffer_RequestedAddressInUse() throws Exception { + mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, TEST_INETADDR_1, false, HOSTNAME_NONE); + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, + TEST_INETADDR_1, HOSTNAME_NONE); + assertNotEquals(TEST_INETADDR_1, offer.getNetAddr()); + } + + @Test + public void testGetOffer_RequestedAddressReserved() throws Exception { + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_RESERVED_ADDR, HOSTNAME_NONE); + assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr()); + } + + @Test + public void testGetOffer_RequestedAddressInvalid() throws Exception { + final Inet4Address invalidAddr = parseAddr4("192.168.42.0"); + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + invalidAddr, HOSTNAME_NONE); + assertNotEquals(invalidAddr, offer.getNetAddr()); + } + + @Test + public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception { + final Inet4Address invalidAddr = parseAddr4("192.168.254.2"); + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + invalidAddr, HOSTNAME_NONE); + assertNotEquals(invalidAddr, offer.getNetAddr()); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testGetOffer_RelayInInvalidSubnet() throws Exception { + mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + parseAddr4("192.168.254.2") /* relayAddr */, INETADDR_UNSPEC, HOSTNAME_NONE); + } + + @Test + public void testRequestLease_SelectingTwice() throws Exception { + DhcpLease lease1 = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, TEST_HOSTNAME_1); + + // Second request from same client for a different address + DhcpLease lease2 = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_2, true /* sidSet */, TEST_HOSTNAME_2); + + assertEquals(TEST_INETADDR_1, lease1.getNetAddr()); + assertEquals(TEST_HOSTNAME_1, lease1.getHostname()); + + assertEquals(TEST_INETADDR_2, lease2.getNetAddr()); + assertEquals(TEST_HOSTNAME_2, lease2.getHostname()); + + // First address freed when client requested a different one: another client can request it + DhcpLease lease3 = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + assertEquals(TEST_INETADDR_1, lease3.getNetAddr()); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_SelectingInvalid() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + parseAddr4("192.168.254.5"), true /* sidSet */, HOSTNAME_NONE); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_SelectingInUse() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_SelectingReserved() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_RESERVED_ADDR, true /* sidSet */, HOSTNAME_NONE); + } + + @Test + public void testRequestLease_InitReboot() throws Exception { + // Request address once + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + + final long newTime = TEST_TIME + 100; + when(mClock.elapsedRealtime()).thenReturn(newTime); + + // init-reboot (sidSet == false): verify configuration + DhcpLease lease = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, false, HOSTNAME_NONE); + assertEquals(TEST_INETADDR_1, lease.getNetAddr()); + assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime()); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_InitRebootWrongAddr() throws Exception { + // Request address once + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + // init-reboot with different requested address + mRepo.requestLease( + CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, TEST_INETADDR_2, false, HOSTNAME_NONE); + } + + @Test + public void testRequestLease_InitRebootUnknownAddr() throws Exception { + // init-reboot with unknown requested address + DhcpLease lease = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_2, false, HOSTNAME_NONE); + // RFC2131 says we should not reply to accommodate other servers, but since we are + // authoritative we allow creating the lease to avoid issues with lost lease DB (same as + // dnsmasq behavior) + assertEquals(TEST_INETADDR_2, lease.getNetAddr()); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_InitRebootWrongSubnet() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + parseAddr4("192.168.254.2"), false /* sidSet */, HOSTNAME_NONE); + } + + @Test + public void testRequestLease_Renewing() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, + INET4_ANY /* clientAddr */, TEST_INETADDR_1 /* reqAddr */, true, HOSTNAME_NONE); + + final long newTime = TEST_TIME + 100; + when(mClock.elapsedRealtime()).thenReturn(newTime); + + // Renewing: clientAddr filled in, no reqAddr + DhcpLease lease = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, + TEST_INETADDR_1 /* clientAddr */, INETADDR_UNSPEC /* reqAddr */, false, + HOSTNAME_NONE); + + assertEquals(TEST_INETADDR_1, lease.getNetAddr()); + assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime()); + } + + @Test + public void testRequestLease_RenewingUnknownAddr() throws Exception { + final long newTime = TEST_TIME + 100; + when(mClock.elapsedRealtime()).thenReturn(newTime); + DhcpLease lease = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, + TEST_INETADDR_1 /* clientAddr */, INETADDR_UNSPEC /* reqAddr */, false, + HOSTNAME_NONE); + // Allows renewing an unknown address if available + assertEquals(TEST_INETADDR_1, lease.getNetAddr()); + assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime()); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_RenewingAddrInUse() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_2, + INET4_ANY /* clientAddr */, TEST_INETADDR_1 /* reqAddr */, true, HOSTNAME_NONE); + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, + TEST_INETADDR_1 /* clientAddr */, INETADDR_UNSPEC /* reqAddr */, false, + HOSTNAME_NONE); + } + + @Test(expected = DhcpLeaseRepository.InvalidAddressException.class) + public void testRequestLease_RenewingInvalidAddr() throws Exception { + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, parseAddr4("192.168.254.2") /* clientAddr */, + INETADDR_UNSPEC /* reqAddr */, false, HOSTNAME_NONE); + } + + @Test + public void testReleaseLease() throws Exception { + DhcpLease lease1 = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + + assertHasLease(lease1); + assertTrue(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1)); + assertNoLease(lease1); + + DhcpLease lease2 = mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, + TEST_INETADDR_1, true /* sidSet */, HOSTNAME_NONE); + + assertEquals(TEST_INETADDR_1, lease2.getNetAddr()); + } + + @Test + public void testReleaseLease_UnknownLease() { + assertFalse(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1)); + } + + @Test + public void testReleaseLease_StableOffer() throws Exception { + for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) { + final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + mRepo.requestLease( + CLIENTID_UNSPEC, mac, INET4_ANY, lease.getNetAddr(), true, + HOSTNAME_NONE); + mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr()); + + // Same lease is offered after it was released + final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + assertEquals(lease.getNetAddr(), newLease.getNetAddr()); + } + } + + @Test + public void testMarkLeaseDeclined() throws Exception { + final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + + mRepo.markLeaseDeclined(lease.getNetAddr()); + + // Same lease is not offered again + final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + assertNotEquals(lease.getNetAddr(), newLease.getNetAddr()); + } + + @Test + public void testMarkLeaseDeclined_UsedIfOutOfAddresses() throws Exception { + // Use a /28 to quickly run out of addresses + mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS); + + mRepo.markLeaseDeclined(TEST_INETADDR_1); + mRepo.markLeaseDeclined(TEST_INETADDR_2); + + // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses + requestAddresses((byte)9); + + // Last 2 addresses: addresses marked declined should be used + final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1); + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY, firstLease.getNetAddr(), true, + HOSTNAME_NONE); + + final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, + INETADDR_UNSPEC /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2); + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY, secondLease.getNetAddr(), true, + HOSTNAME_NONE); + + // Now out of addresses + try { + mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INETADDR_UNSPEC /* relayAddr */, + INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + fail("Repository should be out of addresses and throw"); + } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ } + + assertEquals(TEST_INETADDR_1, firstLease.getNetAddr()); + assertEquals(TEST_HOSTNAME_1, firstLease.getHostname()); + assertEquals(TEST_INETADDR_2, secondLease.getNetAddr()); + assertEquals(TEST_HOSTNAME_2, secondLease.getHostname()); + } + + private void assertNoLease(DhcpLease lease) { + assertFalse("Leases contain " + lease, mRepo.getCommittedLeases().contains(lease)); + } + + private void assertHasLease(DhcpLease lease) { + assertTrue("Leases do not contain " + lease, mRepo.getCommittedLeases().contains(lease)); + } + + private void assertNotDeclined(Inet4Address addr) { + assertFalse("Address is declined: " + addr, mRepo.getDeclinedAddresses().contains(addr)); + } + + private void assertDeclined(Inet4Address addr) { + assertTrue("Address is not declined: " + addr, mRepo.getDeclinedAddresses().contains(addr)); + } +} diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java new file mode 100644 index 000000000000..dfa09a9f205c --- /dev/null +++ b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java @@ -0,0 +1,177 @@ +/* + * 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.net.dhcp; + +import static android.net.dhcp.DhcpServingParams.MTU_UNSET; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static java.net.InetAddress.parseNumericAddress; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.dhcp.DhcpServingParams.InvalidParameterException; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DhcpServingParamsTest { + @NonNull + private DhcpServingParams.Builder mBuilder; + + private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124"))); + private static final long TEST_LEASE_TIME_SECS = 3600L; + private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127"))); + private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2"); + private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20); + private static final int TEST_MTU = 1500; + private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); + + @Before + public void setUp() { + mBuilder = new DhcpServingParams.Builder() + .setDefaultRouters(TEST_DEFAULT_ROUTERS) + .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS) + .setDnsServers(TEST_DNS_SERVERS) + .setServerAddr(TEST_LINKADDR) + .setLinkMtu(TEST_MTU) + .setExcludedAddrs(TEST_EXCLUDED_ADDRS); + } + + @Test + public void testBuild_Immutable() throws InvalidParameterException { + final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS); + final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS); + final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS); + + final DhcpServingParams params = mBuilder + .setDefaultRouters(routers) + .setDnsServers(dnsServers) + .setExcludedAddrs(excludedAddrs) + .build(); + + // Modifications to source objects should not affect builder or final parameters + final Inet4Address addedAddr = parseAddr("192.168.0.223"); + routers.add(addedAddr); + dnsServers.add(addedAddr); + excludedAddrs.add(addedAddr); + + assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters); + assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs); + assertEquals(TEST_DNS_SERVERS, params.dnsServers); + assertEquals(TEST_LINKADDR, params.serverAddr); + assertEquals(TEST_MTU, params.linkMtu); + + assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS); + assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS); + assertContains(params.excludedAddrs, TEST_DNS_SERVERS); + assertContains(params.excludedAddrs, TEST_SERVER_ADDR); + + assertFalse("excludedAddrs should not contain " + addedAddr, + params.excludedAddrs.contains(addedAddr)); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_NegativeLeaseTime() throws InvalidParameterException { + mBuilder.setDhcpLeaseTimeSecs(-1).build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException { + // Set lease time larger than max value for uint32 + mBuilder.setDhcpLeaseTimeSecs(1L << 32).build(); + } + + @Test + public void testBuild_InfiniteLeaseTime() throws InvalidParameterException { + final long infiniteLeaseTime = 0xffffffffL; + final DhcpServingParams params = mBuilder + .setDhcpLeaseTimeSecs(infiniteLeaseTime).build(); + assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs); + assertTrue(params.dhcpLeaseTimeSecs > 0L); + } + + @Test + public void testBuild_UnsetMtu() throws InvalidParameterException { + final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build(); + assertEquals(MTU_UNSET, params.linkMtu); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_MtuTooSmall() throws InvalidParameterException { + mBuilder.setLinkMtu(20).build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_MtuTooLarge() throws InvalidParameterException { + mBuilder.setLinkMtu(65_536).build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_IPv6Addr() throws InvalidParameterException { + mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_PrefixTooLarge() throws InvalidParameterException { + mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_PrefixTooSmall() throws InvalidParameterException { + mBuilder.setDefaultRouters(Collections.singleton(parseAddr("192.168.0.254"))) + .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31)) + .build(); + } + + @Test(expected = InvalidParameterException.class) + public void testBuild_RouterNotInPrefix() throws InvalidParameterException { + mBuilder.setDefaultRouters(Collections.singleton(parseAddr("192.168.254.254"))).build(); + } + + private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) { + for (final T elem : subset) { + assertContains(set, elem); + } + } + + private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) { + assertTrue("Set does not contain " + elem, set.contains(elem)); + } + + @NonNull + private static Inet4Address parseAddr(@NonNull String inet4Addr) { + return (Inet4Address) parseNumericAddress(inet4Addr); + } +} diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk index 9795188559c4..1149b8a8fe40 100644 --- a/tests/privapp-permissions/Android.mk +++ b/tests/privapp-permissions/Android.mk @@ -46,3 +46,19 @@ LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions LOCAL_SRC_FILES:= product/privapp-permissions-test.xml include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := ProductServicesPrivAppPermissionTest +LOCAL_SDK_VERSION := current +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MANIFEST_FILE := product_services/AndroidManifest.xml +LOCAL_PRODUCT_SERVICES_MODULE := true +LOCAL_REQUIRED_MODULES := product_servicesprivapp-permissions-test.xml +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE := product_servicesprivapp-permissions-test.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_SERVICES_ETC)/permissions +LOCAL_SRC_FILES:= product_services/privapp-permissions-test.xml +include $(BUILD_PREBUILT) diff --git a/tests/privapp-permissions/product_services/AndroidManifest.xml b/tests/privapp-permissions/product_services/AndroidManifest.xml new file mode 100644 index 000000000000..511ddee729ca --- /dev/null +++ b/tests/privapp-permissions/product_services/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.framework.permission.privapp.tests.product_services"> + + <!-- MANAGE_USB is signature|privileged --> + <uses-permission android:name="android.permission.MANAGE_USB"/> +</manifest> diff --git a/tests/privapp-permissions/product_services/privapp-permissions-test.xml b/tests/privapp-permissions/product_services/privapp-permissions-test.xml new file mode 100644 index 000000000000..43baebbb0aad --- /dev/null +++ b/tests/privapp-permissions/product_services/privapp-permissions-test.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<permissions> + <privapp-permissions package="com.android.framework.permission.privapp.tests.product_services"> + <permission name="android.permission.MANAGE_USB"/> + </privapp-permissions> +</permissions> diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index 861efd5077fe..69392d66e21f 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -474,9 +474,9 @@ void printXMLBlock(ResXMLTree* block) if (value.dataType == Res_value::TYPE_NULL) { printf("=(null)"); } else if (value.dataType == Res_value::TYPE_REFERENCE) { - printf("=@0x%x", (int)value.data); + printf("=@0x%08x", (int)value.data); } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) { - printf("=?0x%x", (int)value.data); + printf("=?0x%08x", (int)value.data); } else if (value.dataType == Res_value::TYPE_STRING) { printf("=\"%s\"", ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i, diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index b4311c56428b..29e471e581ce 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -398,6 +398,36 @@ int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) { return 0; } +int DumpPackageNameCommand::Action(const std::vector<std::string>& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + xml::Element* manifest_el = loaded_apk->GetManifest()->root.get(); + if (!manifest_el) { + diag_->Error(DiagMessage() << "No AndroidManifest."); + return 1; + } + + xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); + if (!attr) { + diag_->Error(DiagMessage() << "No package name."); + return 1; + } + printer.Println(StringPrintf("%s", attr->value.c_str())); + + return 0; +} + /** Preform no action because a subcommand is required. */ int DumpCommand::Action(const std::vector<std::string>& args) { if (args.size() == 0) { diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 03a4fba133ba..0724d6203e8f 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -115,12 +115,26 @@ class DumpXmlTreeCommand : public Command { std::vector<std::string> files_; }; -/** The default dump command. Preforms no action because a subcommand is required. */ +/** Prints the contents of the resource table from the APK. */ +class DumpPackageNameCommand : public Command { + public: + explicit DumpPackageNameCommand(IDiagnostics* diag) : Command("packagename"), diag_(diag) { + SetDescription("Print the package name of the APK."); + } + + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; +}; + +/** The default dump command. Performs no action because a subcommand is required. */ class DumpCommand : public Command { public: explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) { AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_)); AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(diag_)); AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_)); AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_)); AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_)); diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 55a32c8b512c..c5c78d9d3827 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -357,6 +357,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action["uses-permission"]; manifest_action["uses-permission-sdk-23"]; manifest_action["permission"]; + manifest_action["permission"]["meta-data"] = meta_data_action; manifest_action["permission-tree"]; manifest_action["permission-group"]; manifest_action["uses-configuration"]; @@ -366,6 +367,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action["compatible-screens"]; manifest_action["compatible-screens"]["screen"]; manifest_action["supports-gl-texture"]; + manifest_action["restrict-update"]; + manifest_action["package-verifier"]; manifest_action["meta-data"] = meta_data_action; manifest_action["uses-split"].Action(RequiredNameIsJavaPackage); @@ -387,6 +390,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, uses_static_library_action.Action(RequiredNameIsJavaPackage); uses_static_library_action.Action(RequiredAndroidAttribute("version")); uses_static_library_action.Action(RequiredAndroidAttribute("certDigest")); + uses_static_library_action["additional-certificate"]; if (options_.debug_mode) { application_action.Action([&](xml::Element* el) -> bool { diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh new file mode 100755 index 000000000000..29bf74c7a8b9 --- /dev/null +++ b/tools/aosp/aosp_sha.sh @@ -0,0 +1,18 @@ +#!/bin/bash +LOCAL_DIR="$( dirname ${BASH_SOURCE} )" + +if git branch -vv | grep "^*" | grep "\[aosp/master" > /dev/null; then + # Change appears to be in AOSP + exit 0 +else + # Change appears to be non-AOSP; search for files + git show --name-only --pretty=format: $1 | grep $2 | while read file; do + echo + echo -e "\033[0;31mThe source of truth for '$file' is in AOSP.\033[0m" + echo + echo "If your change contains no confidential details, please upload and merge" + echo "this change at https://android-review.googlesource.com/." + echo + exit 77 + done +fi diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index e519909aa026..8038a3a4f44e 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -349,8 +349,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, argIndex++; } fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { return retry; }\n"); - + fprintf(out, " if (ret >= 0) { break; }\n"); fprintf(out, " {\n"); fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); @@ -360,6 +359,9 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " }\n"); fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); fprintf(out, " }\n"); + fprintf(out, " if (ret < 0) {\n"); + fprintf(out, " note_log_drop();\n"); + fprintf(out, " }\n"); fprintf(out, " return ret;\n"); fprintf(out, "}\n"); fprintf(out, "\n"); @@ -439,7 +441,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, argIndex++; } fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { return retry; }\n"); + fprintf(out, " if (ret >= 0) { break; }\n"); fprintf(out, " {\n"); fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); @@ -450,7 +452,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); fprintf(out, " }\n"); - fprintf(out, " return ret;\n"); + fprintf(out, " if (ret < 0) {\n"); + fprintf(out, " note_log_drop();\n"); + fprintf(out, " }\n"); + fprintf(out, " return ret;\n\n"); fprintf(out, "}\n"); fprintf(out, "\n"); |