diff options
371 files changed, 5307 insertions, 4055 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index bb94275fc409..ba8348337981 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; +import android.annotation.Nullable; import android.app.job.JobInfo; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; @@ -86,9 +87,12 @@ public final class ConnectivityController extends RestrictingController implemen @GuardedBy("mLock") private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>(); - /** List of currently available networks. */ + /** + * Set of currently available networks mapped to their latest network capabilities. Cache the + * latest capabilities to avoid unnecessary calls into ConnectivityManager. + */ @GuardedBy("mLock") - private final ArraySet<Network> mAvailableNetworks = new ArraySet<>(); + private final ArrayMap<Network, NetworkCapabilities> mAvailableNetworks = new ArrayMap<>(); private static final int MSG_DATA_SAVER_TOGGLED = 0; private static final int MSG_UID_RULES_CHANGES = 1; @@ -165,9 +169,8 @@ public final class ConnectivityController extends RestrictingController implemen public boolean isNetworkAvailable(JobStatus job) { synchronized (mLock) { for (int i = 0; i < mAvailableNetworks.size(); ++i) { - final Network network = mAvailableNetworks.valueAt(i); - final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities( - network); + final Network network = mAvailableNetworks.keyAt(i); + final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i); final boolean satisfied = isSatisfied(job, network, capabilities, mConstants); if (DEBUG) { Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network @@ -427,9 +430,33 @@ public final class ConnectivityController extends RestrictingController implemen return false; } + @Nullable + private NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { + if (network == null) { + return null; + } + synchronized (mLock) { + // There is technically a race here if the Network object is reused. This can happen + // only if that Network disconnects and the auto-incrementing network ID in + // ConnectivityService wraps. This should no longer be a concern if/when we only make + // use of asynchronous calls. + if (mAvailableNetworks.get(network) != null) { + return mAvailableNetworks.get(network); + } + + // This should almost never happen because any time a new network connects, the + // NetworkCallback would populate mAvailableNetworks. However, it's currently necessary + // because we also call synchronous methods such as getActiveNetworkForUid. + // TODO(134978280): remove after switching to callback-based APIs + final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network); + mAvailableNetworks.put(network, capabilities); + return capabilities; + } + } + private boolean updateConstraintsSatisfied(JobStatus jobStatus) { final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid()); - final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network); + final NetworkCapabilities capabilities = getNetworkCapabilities(network); return updateConstraintsSatisfied(jobStatus, network, capabilities); } @@ -470,19 +497,13 @@ public final class ConnectivityController extends RestrictingController implemen */ private void updateTrackedJobs(int filterUid, Network filterNetwork) { synchronized (mLock) { - // Since this is a really hot codepath, temporarily cache any - // answers that we get from ConnectivityManager. - final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>(); - boolean changed = false; if (filterUid == -1) { for (int i = mTrackedJobs.size() - 1; i >= 0; i--) { - changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), - filterNetwork, networkToCapabilities); + changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork); } } else { - changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), - filterNetwork, networkToCapabilities); + changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork); } if (changed) { mStateChangedListener.onControllerStateChanged(); @@ -490,18 +511,13 @@ public final class ConnectivityController extends RestrictingController implemen } } - private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork, - ArrayMap<Network, NetworkCapabilities> networkToCapabilities) { + private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) { if (jobs == null || jobs.size() == 0) { return false; } final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid()); - NetworkCapabilities capabilities = networkToCapabilities.get(network); - if (capabilities == null) { - capabilities = mConnManager.getNetworkCapabilities(network); - networkToCapabilities.put(network, capabilities); - } + final NetworkCapabilities capabilities = getNetworkCapabilities(network); final boolean networkMatch = (filterNetwork == null || Objects.equals(filterNetwork, network)); @@ -544,9 +560,9 @@ public final class ConnectivityController extends RestrictingController implemen @Override public void onAvailable(Network network) { if (DEBUG) Slog.v(TAG, "onAvailable: " + network); - synchronized (mLock) { - mAvailableNetworks.add(network); - } + // Documentation says not to call getNetworkCapabilities here but wait for + // onCapabilitiesChanged instead. onCapabilitiesChanged should be called immediately + // after this, so no need to update mAvailableNetworks here. } @Override @@ -554,6 +570,9 @@ public final class ConnectivityController extends RestrictingController implemen if (DEBUG) { Slog.v(TAG, "onCapabilitiesChanged: " + network); } + synchronized (mLock) { + mAvailableNetworks.put(network, capabilities); + } updateTrackedJobs(-1, network); } @@ -630,6 +649,8 @@ public final class ConnectivityController extends RestrictingController implemen pw.println("Available networks:"); pw.increaseIndent(); for (int i = 0; i < mAvailableNetworks.size(); i++) { + pw.print(mAvailableNetworks.keyAt(i)); + pw.print(": "); pw.println(mAvailableNetworks.valueAt(i)); } pw.decreaseIndent(); @@ -667,7 +688,7 @@ public final class ConnectivityController extends RestrictingController implemen mRequestedWhitelistJobs.keyAt(i)); } for (int i = 0; i < mAvailableNetworks.size(); i++) { - Network network = mAvailableNetworks.valueAt(i); + Network network = mAvailableNetworks.keyAt(i); if (network != null) { network.dumpDebug(proto, StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS); diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index ce4b030467a7..3272fdf40062 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -35,7 +35,6 @@ java_library { libs: [ "framework_media_annotation", ], - static_libs: [ "exoplayer2-extractor" ], @@ -101,10 +100,33 @@ java_sdk_library { impl_library_visibility: ["//frameworks/av/apex:__subpackages__"], } - java_library { name: "framework_media_annotation", srcs: [":framework-media-annotation-srcs"], installable: false, sdk_version: "core_current", } + +cc_library_shared { + name: "libmediaparser-jni", + srcs: [ + "jni/android_media_MediaParserJNI.cpp", + ], + header_libs: ["jni_headers"], + shared_libs: [ + "libandroid", + "liblog", + "libmediametrics", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wunreachable-code", + "-Wunused", + ], + apex_available: [ + "com.android.media", + ], + min_sdk_version: "29", +} diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index e4b5d19e67c9..8bdca766e0dd 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -75,6 +75,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Function; /** * Parses media container formats and extracts contained media samples and metadata. @@ -882,6 +884,7 @@ public final class MediaParser { // Private constants. private static final String TAG = "MediaParser"; + private static final String JNI_LIBRARY_NAME = "mediaparser-jni"; private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME; private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME; private static final String TS_MODE_SINGLE_PMT = "single_pmt"; @@ -889,6 +892,14 @@ public final class MediaParser { private static final String TS_MODE_HLS = "hls"; private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6; private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + private static final String MEDIAMETRICS_ELEMENT_SEPARATOR = "|"; + private static final int MEDIAMETRICS_MAX_STRING_SIZE = 200; + private static final int MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH; + /** + * Intentional error introduced to reported metrics to prevent identification of the parsed + * media. Note: Increasing this value may cause older hostside CTS tests to fail. + */ + private static final float MEDIAMETRICS_DITHER = .02f; @IntDef( value = { @@ -920,7 +931,7 @@ public final class MediaParser { @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) { String[] nameAsArray = new String[] {name}; assertValidNames(nameAsArray); - return new MediaParser(outputConsumer, /* sniff= */ false, name); + return new MediaParser(outputConsumer, /* createdByName= */ true, name); } /** @@ -940,7 +951,7 @@ public final class MediaParser { if (parserNames.length == 0) { parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]); } - return new MediaParser(outputConsumer, /* sniff= */ true, parserNames); + return new MediaParser(outputConsumer, /* createdByName= */ false, parserNames); } // Misc static methods. @@ -1052,6 +1063,14 @@ public final class MediaParser { private long mPendingSeekPosition; private long mPendingSeekTimeMicros; private boolean mLoggedSchemeInitDataCreationException; + private boolean mReleased; + + // MediaMetrics fields. + private final boolean mCreatedByName; + private final SparseArray<Format> mTrackFormats; + private String mLastObservedExceptionName; + private long mDurationMillis; + private long mResourceByteCount; // Public methods. @@ -1166,11 +1185,15 @@ public final class MediaParser { if (mExtractorInput == null) { // TODO: For efficiency, the same implementation should be used, by providing a // clearBuffers() method, or similar. + long resourceLength = seekableInputReader.getLength(); + if (mResourceByteCount == 0) { + // For resource byte count metric collection, we only take into account the length + // of the first provided input reader. + mResourceByteCount = resourceLength; + } mExtractorInput = new DefaultExtractorInput( - mExoDataReader, - seekableInputReader.getPosition(), - seekableInputReader.getLength()); + mExoDataReader, seekableInputReader.getPosition(), resourceLength); } mExoDataReader.mInputReader = seekableInputReader; @@ -1195,7 +1218,10 @@ public final class MediaParser { } } if (mExtractor == null) { - throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); + UnrecognizedInputFormatException exception = + UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); + mLastObservedExceptionName = exception.getClass().getName(); + throw exception; } return true; } @@ -1223,8 +1249,13 @@ public final class MediaParser { int result; try { result = mExtractor.read(mExtractorInput, mPositionHolder); - } catch (ParserException e) { - throw new ParsingException(e); + } catch (Exception e) { + mLastObservedExceptionName = e.getClass().getName(); + if (e instanceof ParserException) { + throw new ParsingException((ParserException) e); + } else { + throw e; + } } if (result == Extractor.RESULT_END_OF_INPUT) { mExtractorInput = null; @@ -1264,21 +1295,64 @@ public final class MediaParser { * invoked. */ public void release() { - // TODO: Dump media metrics here. mExtractorInput = null; mExtractor = null; + if (mReleased) { + // Nothing to do. + return; + } + mReleased = true; + + String trackMimeTypes = buildMediaMetricsString(format -> format.sampleMimeType); + String trackCodecs = buildMediaMetricsString(format -> format.codecs); + int videoWidth = -1; + int videoHeight = -1; + for (int i = 0; i < mTrackFormats.size(); i++) { + Format format = mTrackFormats.valueAt(i); + if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) { + videoWidth = format.width; + videoHeight = format.height; + break; + } + } + + String alteredParameters = + String.join( + MEDIAMETRICS_ELEMENT_SEPARATOR, + mParserParameters.keySet().toArray(new String[0])); + alteredParameters = + alteredParameters.substring( + 0, + Math.min( + alteredParameters.length(), + MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH)); + + nativeSubmitMetrics( + mParserName, + mCreatedByName, + String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool), + mLastObservedExceptionName, + addDither(mResourceByteCount), + addDither(mDurationMillis), + trackMimeTypes, + trackCodecs, + alteredParameters, + videoWidth, + videoHeight); } // Private methods. - private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) { + private MediaParser( + OutputConsumer outputConsumer, boolean createdByName, String... parserNamesPool) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { throw new UnsupportedOperationException("Android version must be R or greater."); } mParserParameters = new HashMap<>(); mOutputConsumer = outputConsumer; mParserNamesPool = parserNamesPool; - mParserName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0]; + mCreatedByName = createdByName; + mParserName = createdByName ? parserNamesPool[0] : PARSER_NAME_UNKNOWN; mPositionHolder = new PositionHolder(); mExoDataReader = new InputReadingDataReader(); removePendingSeek(); @@ -1286,6 +1360,24 @@ public final class MediaParser { mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter(); mSchemeInitDataConstructor = getSchemeInitDataConstructor(); mMuxedCaptionFormats = new ArrayList<>(); + + // MediaMetrics. + mTrackFormats = new SparseArray<>(); + mLastObservedExceptionName = ""; + mDurationMillis = -1; + } + + private String buildMediaMetricsString(Function<Format, String> formatFieldGetter) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < mTrackFormats.size(); i++) { + if (i > 0) { + stringBuilder.append(MEDIAMETRICS_ELEMENT_SEPARATOR); + } + String fieldValue = formatFieldGetter.apply(mTrackFormats.valueAt(i)); + stringBuilder.append(fieldValue != null ? fieldValue : ""); + } + return stringBuilder.substring( + 0, Math.min(stringBuilder.length(), MEDIAMETRICS_MAX_STRING_SIZE)); } private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) { @@ -1528,6 +1620,10 @@ public final class MediaParser { @Override public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { + long durationUs = exoplayerSeekMap.getDurationUs(); + if (durationUs != C.TIME_UNSET) { + mDurationMillis = C.usToMs(durationUs); + } if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) { ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap; MediaFormat mediaFormat = new MediaFormat(); @@ -1575,6 +1671,7 @@ public final class MediaParser { @Override public void format(Format format) { + mTrackFormats.put(mTrackIndex, format); mOutputConsumer.onTrackDataFound( mTrackIndex, new TrackData( @@ -2031,6 +2128,20 @@ public final class MediaParser { return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position); } + /** + * Introduces random error to the given metric value in order to prevent the identification of + * the parsed media. + */ + private static long addDither(long value) { + // Generate a random in [0, 1]. + double randomDither = ThreadLocalRandom.current().nextFloat(); + // Clamp the random number to [0, 2 * MEDIAMETRICS_DITHER]. + randomDither *= 2 * MEDIAMETRICS_DITHER; + // Translate the random number to [1 - MEDIAMETRICS_DITHER, 1 + MEDIAMETRICS_DITHER]. + randomDither += 1 - MEDIAMETRICS_DITHER; + return value != -1 ? (long) (value * randomDither) : -1; + } + private static void assertValidNames(@NonNull String[] names) { for (String name : names) { if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) { @@ -2070,9 +2181,26 @@ public final class MediaParser { } } + // Native methods. + + private native void nativeSubmitMetrics( + String parserName, + boolean createdByName, + String parserPool, + String lastObservedExceptionName, + long resourceByteCount, + long durationMillis, + String trackMimeTypes, + String trackCodecs, + String alteredParameters, + int videoWidth, + int videoHeight); + // Static initialization. static { + System.loadLibrary(JNI_LIBRARY_NAME); + // Using a LinkedHashMap to keep the insertion order when iterating over the keys. LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>(); // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering, @@ -2125,6 +2253,15 @@ public final class MediaParser { // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters // instead. Checking that the value is a List is insufficient to catch wrong parameter // value types. + int sumOfParameterNameLengths = + expectedTypeByParameterName.keySet().stream() + .map(String::length) + .reduce(0, Integer::sum); + sumOfParameterNameLengths += PARAMETER_EXPOSE_CAPTION_FORMATS.length(); + // Add space for any required separators. + MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH = + sumOfParameterNameLengths + expectedTypeByParameterName.size(); + EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName); } } diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp new file mode 100644 index 000000000000..7fc4628984f5 --- /dev/null +++ b/apex/media/framework/jni/android_media_MediaParserJNI.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2020, 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 <jni.h> +#include <media/MediaMetrics.h> + +#define JNI_FUNCTION(RETURN_TYPE, NAME, ...) \ + extern "C" { \ + JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \ + ##__VA_ARGS__); \ + } \ + JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \ + ##__VA_ARGS__) + +namespace { + +constexpr char kMediaMetricsKey[] = "mediaparser"; + +constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName"; +constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName"; +constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool"; +constexpr char kAttributeLastException[] = "android.media.mediaparser.lastException"; +constexpr char kAttributeResourceByteCount[] = "android.media.mediaparser.resourceByteCount"; +constexpr char kAttributeDurationMillis[] = "android.media.mediaparser.durationMillis"; +constexpr char kAttributeTrackMimeTypes[] = "android.media.mediaparser.trackMimeTypes"; +constexpr char kAttributeTrackCodecs[] = "android.media.mediaparser.trackCodecs"; +constexpr char kAttributeAlteredParameters[] = "android.media.mediaparser.alteredParameters"; +constexpr char kAttributeVideoWidth[] = "android.media.mediaparser.videoWidth"; +constexpr char kAttributeVideoHeight[] = "android.media.mediaparser.videoHeight"; + +// Util class to handle string resource management. +class JstringHandle { +public: + JstringHandle(JNIEnv* env, jstring value) : mEnv(env), mJstringValue(value) { + mCstringValue = env->GetStringUTFChars(value, /* isCopy= */ nullptr); + } + + ~JstringHandle() { + if (mCstringValue != nullptr) { + mEnv->ReleaseStringUTFChars(mJstringValue, mCstringValue); + } + } + + [[nodiscard]] const char* value() const { + return mCstringValue != nullptr ? mCstringValue : ""; + } + + JNIEnv* mEnv; + jstring mJstringValue; + const char* mCstringValue; +}; + +} // namespace + +JNI_FUNCTION(void, nativeSubmitMetrics, jstring parserNameJstring, jboolean createdByName, + jstring parserPoolJstring, jstring lastExceptionJstring, jlong resourceByteCount, + jlong durationMillis, jstring trackMimeTypesJstring, jstring trackCodecsJstring, + jstring alteredParameters, jint videoWidth, jint videoHeight) { + mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey)); + mediametrics_setCString(item, kAttributeParserName, + JstringHandle(env, parserNameJstring).value()); + mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0); + mediametrics_setCString(item, kAttributeParserPool, + JstringHandle(env, parserPoolJstring).value()); + mediametrics_setCString(item, kAttributeLastException, + JstringHandle(env, lastExceptionJstring).value()); + mediametrics_setInt64(item, kAttributeResourceByteCount, resourceByteCount); + mediametrics_setInt64(item, kAttributeDurationMillis, durationMillis); + mediametrics_setCString(item, kAttributeTrackMimeTypes, + JstringHandle(env, trackMimeTypesJstring).value()); + mediametrics_setCString(item, kAttributeTrackCodecs, + JstringHandle(env, trackCodecsJstring).value()); + mediametrics_setCString(item, kAttributeAlteredParameters, + JstringHandle(env, alteredParameters).value()); + mediametrics_setInt32(item, kAttributeVideoWidth, videoWidth); + mediametrics_setInt32(item, kAttributeVideoHeight, videoHeight); + mediametrics_selfRecord(item); + mediametrics_delete(item); +} diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index dc1612575f38..13bf197aa9dc 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -554,6 +554,10 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8 return NO_ERROR; } if (!args[0].compare(String8("section"))) { + if (argCount == 1) { + fprintf(out, "Not enough arguments for section\n"); + return NO_ERROR; + } int id = atoi(args[1]); int idx = 0; while (SECTION_LIST[idx] != NULL) { diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 38d378169ec9..3e21e149b3b6 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -364,6 +364,18 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000; + /** + * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled, + * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected, + * but instead passed through as one-finger gestures. In addition, three-finger swipes from the + * bottom of the screen are not detected, and instead are passed through unchanged. If {@link + * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect. + * + * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + * @hide + */ + public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000; + /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -1261,6 +1273,8 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; case FLAG_REQUEST_MULTI_FINGER_GESTURES: return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; + case FLAG_REQUEST_2_FINGER_PASSTHROUGH: + return "FLAG_REQUEST_2_FINGER_PASSTHROUGH"; case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; case FLAG_REPORT_VIEW_IDS: diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java index af74b036a796..5dc6e602e5d6 100644 --- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java +++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java @@ -16,16 +16,23 @@ package android.accounts; import android.app.Activity; -import android.content.res.Resources; -import android.os.Bundle; -import android.widget.TextView; -import android.widget.LinearLayout; -import android.view.View; -import android.view.LayoutInflater; +import android.app.ActivityTaskManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + import com.android.internal.R; import java.io.IOException; @@ -42,11 +49,15 @@ public class GrantCredentialsPermissionActivity extends Activity implements View private Account mAccount; private String mAuthTokenType; private int mUid; + private int mCallingUid; private Bundle mResultBundle = null; protected LayoutInflater mInflater; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().addSystemFlags( + android.view.WindowManager.LayoutParams + .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); setContentView(R.layout.grant_credentials_permission); setTitle(R.string.grant_permissions_header_text); @@ -74,6 +85,20 @@ public class GrantCredentialsPermissionActivity extends Activity implements View return; } + try { + IBinder activityToken = getActivityToken(); + mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken); + } catch (RemoteException re) { + // Couldn't figure out caller details + Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re); + } + + if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) { + setResult(Activity.RESULT_CANCELED); + finish(); + return; + } + String accountTypeLabel; try { accountTypeLabel = getAccountLabel(mAccount); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 80d2e6c60f69..4aedfeefb72b 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1275,10 +1275,10 @@ public class ActivityOptions { } /** - * Sets the id of the display where activity should be launched. - * An app can launch activities on public displays or private displays that are owned by the app - * or where an app already has activities. Otherwise, trying to launch on a private display - * or providing an invalid display id will result in an exception. + * Sets the id of the display where the activity should be launched. + * An app can launch activities on public displays or displays where the app already has + * activities. Otherwise, trying to launch on a private display or providing an invalid display + * id will result in an exception. * <p> * Setting launch display id will be ignored on devices that don't have * {@link android.content.pm.PackageManager#FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS}. diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 92b0da1c761f..098d090b5e30 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -105,7 +105,8 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd public ActivityView( @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay) { - this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false); + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + false /* disableSurfaceViewBackgroundLayer */); } /** @hide */ @@ -113,12 +114,22 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay, boolean disableSurfaceViewBackgroundLayer) { + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + disableSurfaceViewBackgroundLayer, false /* useTrustedDisplay */); + } + + // TODO(b/162901735): Refactor ActivityView with Builder + /** @hide */ + public ActivityView( + @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean disableSurfaceViewBackgroundLayer, boolean useTrustedDisplay) { super(context, attrs, defStyle); if (useTaskOrganizer()) { mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this); } else { mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance, - usePublicVirtualDisplay); + usePublicVirtualDisplay, useTrustedDisplay); } mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer); // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 31ab2248236d..ba547b74f106 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -31,8 +31,10 @@ import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.database.DatabaseUtils; @@ -52,6 +54,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserManager; +import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LongSparseArray; @@ -1137,7 +1140,7 @@ public class AppOpsManager { public static final int OP_RECORD_AUDIO_HOTWORD = 102; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final int _NUM_OP = 104; /** Access to coarse location information. */ @@ -7610,8 +7613,9 @@ public class AppOpsManager { collectNotedOpForSelf(op, proxiedAttributionTag); } else if (collectionMode == COLLECT_SYNC // Only collect app-ops when the proxy is trusted - && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1, - myUid) == PackageManager.PERMISSION_GRANTED) { + && (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1, + myUid) == PackageManager.PERMISSION_GRANTED + || isTrustedVoiceServiceProxy(mContext, mContext.getOpPackageName(), op))) { collectNotedOpSync(op, proxiedAttributionTag); } } @@ -7623,6 +7627,43 @@ public class AppOpsManager { } /** + * Checks if the voice recognition service is a trust proxy. + * + * @return {@code true} if the package is a trust voice recognition service proxy + * @hide + */ + public static boolean isTrustedVoiceServiceProxy(Context context, String packageName, + int code) { + // This is a workaround for R QPR, new API change is not allowed. We only allow the current + // voice recognizer is also the voice interactor to noteproxy op. + if (code != OP_RECORD_AUDIO) { + return false; + } + final String voiceRecognitionComponent = Settings.Secure.getString( + context.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE); + + final String voiceRecognitionServicePackageName = + getComponentPackageNameFromString(voiceRecognitionComponent); + return (Objects.equals(packageName, voiceRecognitionServicePackageName)) + && isPackagePreInstalled(context, packageName); + } + + private static String getComponentPackageNameFromString(String from) { + ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null; + return componentName != null ? componentName.getPackageName() : ""; + } + + private static boolean isPackagePreInstalled(Context context, String packageName) { + try { + final PackageManager pm = context.getPackageManager(); + final ApplicationInfo info = pm.getApplicationInfo(packageName, 0); + return ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + /** * Do a quick check for whether an application might be able to perform an operation. * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String, * String, String)} or {@link #startOp(int, int, String, boolean, String, String)} for your diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 7be661b957c0..b45f3893db8c 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -286,7 +286,7 @@ public final class LoadedApk { return mSecurityViolation; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public CompatibilityInfo getCompatibilityInfo() { return mDisplayAdjustments.getCompatibilityInfo(); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 6edc8ea6a3a6..2f99cf107754 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4261,6 +4261,9 @@ public class DevicePolicyManager { * This method can be called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to lock the parent profile. * <p> + * NOTE: on {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, this + * method doesn't turn off the screen as it would be a driving safety distraction. + * <p> * Equivalent to calling {@link #lockNow(int)} with no flags. * * @throws SecurityException if the calling application does not own an active administrator @@ -4304,6 +4307,9 @@ public class DevicePolicyManager { * Calling the method twice in this order ensures that all users are locked and does not * stop the device admin on the managed profile from issuing a second call to lock its own * profile. + * <p> + * NOTE: on {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, this + * method doesn't turn off the screen as it would be a driving safety distraction. * * @param flags May be 0 or {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}. * @throws SecurityException if the calling application does not own an active administrator diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd1eea51f8af..46be54814dc9 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -153,6 +153,7 @@ public abstract class SliceProvider extends ContentProvider { */ public static final String EXTRA_PKG = "pkg"; /** + * @Deprecated provider pkg is now being extracted in SlicePermissionActivity * @hide */ public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java index 7b567b4098e7..f43a9e8cab9d 100644 --- a/core/java/android/bluetooth/BluetoothCodecStatus.java +++ b/core/java/android/bluetooth/BluetoothCodecStatus.java @@ -18,6 +18,7 @@ package android.bluetooth; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -39,7 +40,7 @@ public final class BluetoothCodecStatus implements Parcelable { * This extra represents the current codec status of the A2DP * profile. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS"; @@ -198,7 +199,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return the current codec configuration */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public @Nullable BluetoothCodecConfig getCodecConfig() { return mCodecConfig; } @@ -208,7 +209,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs local capabilities */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() { return mCodecsLocalCapabilities; } @@ -218,7 +219,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs selectable capabilities */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() { return mCodecsSelectableCapabilities; } diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index adb7e2f773a9..57d1411aa68a 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -80,7 +80,7 @@ public final class BluetoothHeadset implements BluetoothProfile { /** * Intent used to broadcast the change in the Audio Connection state of the - * A2DP profile. + * HDP profile. * * <p>This intent will have 3 extras: * <ul> diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index 7733dc14ace4..903d1296fb87 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -47,6 +47,7 @@ public final class AssociationRequest implements Parcelable { private final boolean mSingleDevice; private final List<DeviceFilter<?>> mDeviceFilters; + private String mCallingPackage; private AssociationRequest( boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) { @@ -58,6 +59,7 @@ public final class AssociationRequest implements Parcelable { this( in.readByte() != 0, in.readParcelableList(new ArrayList<>(), AssociationRequest.class.getClassLoader())); + setCallingPackage(in.readString()); } /** @hide */ @@ -73,32 +75,45 @@ public final class AssociationRequest implements Parcelable { return mDeviceFilters; } + /** @hide */ + public String getCallingPackage() { + return mCallingPackage; + } + + /** @hide */ + public void setCallingPackage(String pkg) { + mCallingPackage = pkg; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AssociationRequest that = (AssociationRequest) o; - return mSingleDevice == that.mSingleDevice && - Objects.equals(mDeviceFilters, that.mDeviceFilters); + return mSingleDevice == that.mSingleDevice + && Objects.equals(mDeviceFilters, that.mDeviceFilters) + && Objects.equals(mCallingPackage, that.mCallingPackage); } @Override public int hashCode() { - return Objects.hash(mSingleDevice, mDeviceFilters); + return Objects.hash(mSingleDevice, mDeviceFilters, mCallingPackage); } @Override public String toString() { - return "AssociationRequest{" + - "mSingleDevice=" + mSingleDevice + - ", mDeviceFilters=" + mDeviceFilters + - '}'; + return "AssociationRequest{" + + "mSingleDevice=" + mSingleDevice + + ", mDeviceFilters=" + mDeviceFilters + + ", mCallingPackage=" + mCallingPackage + + '}'; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByte((byte) (mSingleDevice ? 1 : 0)); dest.writeParcelableList(mDeviceFilters, flags); + dest.writeString(mCallingPackage); } @Override diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index 8b411d5fe031..b290679c9fcc 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -119,8 +119,9 @@ public class CrossProfileApps { * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a * {@link SecurityException} will be thrown. * @param callingActivity The activity to start the new activity from for the purposes of - * deciding which task the new activity should belong to. If {@code null}, the activity - * will always be started in a new task. + * passing back any result and deciding which task the new activity should belong to. If + * {@code null}, the activity will always be started in a new task and no result will be + * returned. */ @RequiresPermission(anyOf = { android.Manifest.permission.INTERACT_ACROSS_PROFILES, @@ -146,8 +147,9 @@ public class CrossProfileApps { * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a * {@link SecurityException} will be thrown. * @param callingActivity The activity to start the new activity from for the purposes of - * deciding which task the new activity should belong to. If {@code null}, the activity - * will always be started in a new task. + * passing back any result and deciding which task the new activity should belong to. If + * {@code null}, the activity will always be started in a new task and no result will be + * returned. * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}. */ @RequiresPermission(anyOf = { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 50ef08a9598a..1d914bbc3e33 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -92,6 +92,11 @@ import java.util.Set; * packages that are currently installed on the device. * * You can find this class through {@link Context#getPackageManager}. + * + * <p class="note"><strong>Note: </strong>If your app targets Android 11 (API level 30) or + * higher, the methods in this class each return a filtered list of apps. Learn more about how to + * <a href="/training/basics/intents/package-visibility">manage package visibility</a>. + * </p> */ public abstract class PackageManager { private static final String TAG = "PackageManager"; @@ -1686,6 +1691,15 @@ public abstract class PackageManager { public static final int DELETE_FAILED_USED_SHARED_LIBRARY = -6; /** + * Deletion failed return code: this is passed to the + * {@link IPackageDeleteObserver} if the system failed to delete the package + * because there is an app pinned. + * + * @hide + */ + public static final int DELETE_FAILED_APP_PINNED = -7; + + /** * Return code that is passed to the {@link IPackageMoveObserver} when the * package has been successfully moved by the system. * @@ -7622,6 +7636,7 @@ public abstract class PackageManager { case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED"; case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED"; case DELETE_FAILED_USED_SHARED_LIBRARY: return "DELETE_FAILED_USED_SHARED_LIBRARY"; + case DELETE_FAILED_APP_PINNED: return "DELETE_FAILED_APP_PINNED"; default: return Integer.toString(status); } } @@ -7636,6 +7651,7 @@ public abstract class PackageManager { case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED; case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; case DELETE_FAILED_USED_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case DELETE_FAILED_APP_PINNED: return PackageInstaller.STATUS_FAILURE_BLOCKED; default: return PackageInstaller.STATUS_FAILURE; } } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 4f3c0cb029b8..32aa1c2ed7aa 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2772,7 +2772,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </ol> * </li> * <li>Setting {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to values different than 1.0 and - * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be windowboxing at the same time is undefined behavior.</li> + * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be windowboxing at the same time are not supported. In this + * case, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be the active + * array.</li> * </ul> * <p>LEGACY capability devices will only support CENTER_ONLY cropping.</p> * <p><b>Possible values:</b> diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index cd137078818c..37e12809467d 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -234,7 +234,7 @@ public abstract class CameraDevice implements AutoCloseable { * @see StreamConfigurationMap#getOutputFormats() * @see StreamConfigurationMap#getOutputSizes(int) * @see StreamConfigurationMap#getOutputSizes(Class) - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. */ @@ -249,7 +249,7 @@ public abstract class CameraDevice implements AutoCloseable { * * @see #createCaptureSession * @see OutputConfiguration - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. */ @@ -285,7 +285,7 @@ public abstract class CameraDevice implements AutoCloseable { * @see StreamConfigurationMap#getOutputSizes * @see android.media.ImageWriter * @see android.media.ImageReader - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. */ @@ -302,7 +302,7 @@ public abstract class CameraDevice implements AutoCloseable { * * @see #createReprocessableCaptureSession * @see OutputConfiguration - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. */ @@ -340,7 +340,7 @@ public abstract class CameraDevice implements AutoCloseable { * @see CameraCaptureSession#captureBurst * @see CameraCaptureSession#setRepeatingBurst * @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. */ @@ -413,7 +413,7 @@ public abstract class CameraDevice implements AutoCloseable { * @see #createReprocessableCaptureSession * @see CameraCaptureSession * @see OutputConfiguration - * @deprecated Please use @{link + * @deprecated Please use {@link * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the * full set of configuration options available. * @hide diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 2b633b5c5643..66e78bbc2f22 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -2243,7 +2243,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p> * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} * must only be used for letterboxing or pillarboxing of the sensor active array, and no - * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p> + * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0. If + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be + * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be + * the active array.</p> * <p><b>Range of valid values:</b><br> * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 41f4df7dbc99..ded7c8a8777e 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2473,7 +2473,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p> * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} * must only be used for letterboxing or pillarboxing of the sensor active array, and no - * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p> + * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0. If + * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be + * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be + * the active array.</p> * <p><b>Range of valid values:</b><br> * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 920d34f09819..19f4cd6e991a 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -73,6 +73,7 @@ import android.util.Range; import android.util.Size; import dalvik.annotation.optimization.FastNative; +import dalvik.system.VMRuntime; import java.io.IOException; import java.nio.ByteBuffer; @@ -352,6 +353,7 @@ public class CameraMetadataNative implements Parcelable { if (mMetadataPtr == 0) { throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); } + updateNativeAllocation(); } /** @@ -363,6 +365,7 @@ public class CameraMetadataNative implements Parcelable { if (mMetadataPtr == 0) { throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); } + updateNativeAllocation(); } /** @@ -444,6 +447,7 @@ public class CameraMetadataNative implements Parcelable { public void readFromParcel(Parcel in) { nativeReadFromParcel(in, mMetadataPtr); + updateNativeAllocation(); } /** @@ -534,6 +538,11 @@ public class CameraMetadataNative implements Parcelable { // Delete native pointer, but does not clear it nativeClose(mMetadataPtr); mMetadataPtr = 0; + + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeFree(mBufferSize); + } + mBufferSize = 0; } private <T> T getBase(CameraCharacteristics.Key<T> key) { @@ -1646,9 +1655,26 @@ public class CameraMetadataNative implements Parcelable { return true; } + private void updateNativeAllocation() { + long currentBufferSize = nativeGetBufferSize(mMetadataPtr); + + if (currentBufferSize != mBufferSize) { + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeFree(mBufferSize); + } + + mBufferSize = currentBufferSize; + + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeAllocation(mBufferSize); + } + } + } + private int mCameraId = -1; private boolean mHasMandatoryConcurrentStreams = false; private Size mDisplaySize = new Size(0, 0); + private long mBufferSize = 0; /** * Set the current camera Id. @@ -1706,6 +1732,8 @@ public class CameraMetadataNative implements Parcelable { private static synchronized native boolean nativeIsEmpty(long ptr); @FastNative private static synchronized native int nativeGetEntryCount(long ptr); + @FastNative + private static synchronized native long nativeGetBufferSize(long ptr); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @FastNative @@ -1745,6 +1773,8 @@ public class CameraMetadataNative implements Parcelable { mCameraId = other.mCameraId; mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams; mDisplaySize = other.mDisplaySize; + updateNativeAllocation(); + other.updateNativeAllocation(); } /** diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 9271d0e05fa0..7a383d993389 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -870,38 +870,77 @@ public final class DisplayManager { public interface DeviceConfig { /** - * Key for refresh rate in the zone defined by thresholds. + * Key for refresh rate in the low zone defined by thresholds. * + * Note that the name and value don't match because they were added before we had a high + * zone to consider. * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultZoneBehavior */ - String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone"; + String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone"; /** - * Key for accessing the display brightness thresholds for the configured refresh rate zone. + * Key for accessing the low display brightness thresholds for the configured refresh + * rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). * + * Note that the name and value don't match because they were added before we had a high + * zone to consider. + * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @hide */ - String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS = + String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_brightness_thresholds"; /** - * Key for accessing the ambient brightness thresholds for the configured refresh rate zone. - * The value will be a pair of comma separated integers representing the minimum and maximum - * thresholds of the zone, respectively, in lux. + * Key for accessing the low ambient brightness thresholds for the configured refresh + * rate zone. The value will be a pair of comma separated integers representing the minimum + * and maximum thresholds of the zone, respectively, in lux. + * + * Note that the name and value don't match because they were added before we had a high + * zone to consider. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate * @hide */ - String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS = + String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; + /** + * Key for refresh rate in the high zone defined by thresholds. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.integer#config_fixedRefreshRateInHighZone + */ + String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone"; /** + * Key for accessing the display brightness thresholds for the configured refresh rate zone. + * The value will be a pair of comma separated integers representing the minimum and maximum + * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate + * @hide + */ + String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS = + "fixed_refresh_rate_high_display_brightness_thresholds"; + + /** + * Key for accessing the ambient brightness thresholds for the configured refresh rate zone. + * The value will be a pair of comma separated integers representing the minimum and maximum + * thresholds of the zone, respectively, in lux. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate + * @hide + */ + String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS = + "fixed_refresh_rate_high_ambient_brightness_thresholds"; + /** * Key for default peak refresh rate * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 527495edce67..40c3d87e4f36 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -16,11 +16,11 @@ package android.inputmethodservice; -import static android.graphics.Color.TRANSPARENT; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -69,7 +69,9 @@ import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowInsets.Side; +import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; @@ -103,7 +105,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Collections; +import java.util.ArrayList; /** * InputMethodService provides a standard implementation of an InputMethod, @@ -849,10 +851,19 @@ public class InputMethodService extends AbstractInputMethodService { /** Set region of the keyboard to be avoided from back gesture */ private void setImeExclusionRect(int visibleTopInsets) { - View inputFrameRootView = mInputFrame.getRootView(); - Rect r = new Rect(0, visibleTopInsets, inputFrameRootView.getWidth(), - inputFrameRootView.getHeight()); - inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r)); + View rootView = mInputFrame.getRootView(); + android.graphics.Insets systemGesture = + rootView.getRootWindowInsets().getInsetsIgnoringVisibility(Type.systemGestures()); + ArrayList<Rect> exclusionRects = new ArrayList<>(); + exclusionRects.add(new Rect(0, + visibleTopInsets, + systemGesture.left, + rootView.getHeight())); + exclusionRects.add(new Rect(rootView.getWidth() - systemGesture.right, + visibleTopInsets, + rootView.getWidth(), + rootView.getHeight())); + rootView.setSystemGestureExclusionRects(exclusionRects); } /** @@ -1202,22 +1213,24 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().getAttributes().setFitInsetsTypes(navigationBars()); + mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars()); mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM); - mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true); - // Our window will extend into the status bar area no matter the bar is visible or not. - // We don't want the ColorView to be visible when status bar is shown. - mWindow.getWindow().setStatusBarColor(TRANSPARENT); - - // Automotive devices may request the navigation bar to be hidden when the IME shows up - // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible - // screen real estate. When this happens, the IME window should animate from the bottom of - // the screen to reduce the jank that happens from the lack of synchronization between the - // bottom system window and the IME window. + // IME layout should always be inset by navigation bar, no matter its current visibility, + // unless automotive requests it. Automotive devices may request the navigation bar to be + // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard) + // in order to maximize the visible screen real estate. When this happens, the IME window + // should animate from the bottom of the screen to reduce the jank that happens from the + // lack of synchronization between the bottom system window and the IME window. if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) { mWindow.getWindow().setDecorFitsSystemWindows(false); } + mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( + (v, insets) -> v.onApplyWindowInsets( + new WindowInsets.Builder(insets).setInsets( + navigationBars(), + insets.getInsetsIgnoringVisibility(navigationBars())) + .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set // by default (but IME developers can opt this out later if they want a new behavior). diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index d23d2eca7603..dfc9d5dc0deb 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -94,6 +94,8 @@ interface IPowerManager boolean isAmbientDisplaySuppressedForToken(String token); // returns whether ambient display is suppressed by any app with any token. boolean isAmbientDisplaySuppressed(); + // returns whether ambient display is suppressed by the given app with the given token. + boolean isAmbientDisplaySuppressedForTokenByApp(String token, int appUid); // Forces the system to suspend even if there are held wakelocks. boolean forceSuspend(); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 49b4e0024fc2..bfbdf62d39bb 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2121,6 +2121,27 @@ public final class PowerManager { } /** + * Returns true if ambient display is suppressed by the given {@code appUid} with the given + * {@code token}. + * + * <p>This method will return false if {@link #isAmbientDisplayAvailable()} is false. + * + * @param token The identifier of the ambient display suppression. + * @param appUid The uid of the app that suppressed ambient display. + * @hide + */ + @RequiresPermission(allOf = { + android.Manifest.permission.READ_DREAM_STATE, + android.Manifest.permission.READ_DREAM_SUPPRESSION }) + public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) { + try { + return mService.isAmbientDisplaySuppressedForTokenByApp(token, appUid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns the reason the phone was last shutdown. Calling app must have the * {@link android.Manifest.permission#DEVICE_POWER} permission to request this information. * @return Reason for shutdown as an int, {@link #SHUTDOWN_REASON_UNKNOWN} if the file could diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 1a59e8d34547..b704d66d8e41 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -218,8 +218,15 @@ public abstract class DocumentsProvider extends ContentProvider { } /** {@hide} */ - private void enforceTree(Uri documentUri) { - if (isTreeUri(documentUri)) { + private void enforceTreeForExtraUris(Bundle extras) { + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + } + + /** {@hide} */ + private void enforceTree(@Nullable Uri documentUri) { + if (documentUri != null && isTreeUri(documentUri)) { final String parent = getTreeDocumentId(documentUri); final String child = getDocumentId(documentUri); if (Objects.equals(parent, child)) { @@ -232,6 +239,10 @@ public abstract class DocumentsProvider extends ContentProvider { } } + private Uri validateIncomingNullableUri(@Nullable Uri uri) { + return uri == null ? null : validateIncomingUri(uri); + } + /** * Create a new document and return its newly generated * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new @@ -1076,11 +1087,21 @@ public abstract class DocumentsProvider extends ContentProvider { final Context context = getContext(); final Bundle out = new Bundle(); + // If the URI is a tree URI performs some validation. + enforceTreeForExtraUris(extras); + + final Uri extraUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_URI)); + final Uri extraTargetUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + final Uri extraParentUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + if (METHOD_EJECT_ROOT.equals(method)) { // Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for // MANAGE_DOCUMENTS or associated URI permission here instead - final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri rootUri = extraUri; enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingAttributionTag(), null); @@ -1090,7 +1111,7 @@ public abstract class DocumentsProvider extends ContentProvider { return out; } - final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri documentUri = extraUri; final String authority = documentUri.getAuthority(); final String documentId = DocumentsContract.getDocumentId(documentUri); @@ -1099,14 +1120,11 @@ public abstract class DocumentsProvider extends ContentProvider { "Requested authority " + authority + " doesn't match provider " + mAuthority); } - // If the URI is a tree URI performs some validation. - enforceTree(documentUri); - if (METHOD_IS_CHILD_DOCUMENT.equals(method)) { enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingAttributionTag(), null); - final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri childUri = extraTargetUri; final String childAuthority = childUri.getAuthority(); final String childId = DocumentsContract.getDocumentId(childUri); @@ -1173,7 +1191,7 @@ public abstract class DocumentsProvider extends ContentProvider { revokeDocumentPermission(documentId); } else if (METHOD_COPY_DOCUMENT.equals(method)) { - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceReadPermissionInner(documentUri, getCallingPackage(), @@ -1197,9 +1215,9 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_MOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceWritePermissionInner(documentUri, getCallingPackage(), @@ -1225,7 +1243,7 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_REMOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); enforceReadPermissionInner(parentSourceUri, getCallingPackage(), diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 300bb7603722..6e9cf61968a0 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7884,6 +7884,12 @@ public final class Settings { public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on"; /** + * The last computed night mode bool the last time the phone was on + * @hide + */ + public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed"; + + /** * The current night mode that has been overridden to turn off by the system. Owned * and controlled by UiModeManagerService. Constants are as per * UiModeManager. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 819462190d9c..81e6d42ec056 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3268,8 +3268,8 @@ public final class ViewRootImpl implements ViewParent, // Note: must be done after the focus change callbacks, // so all of the view state is set up correctly. - mImeFocusController.onPostWindowFocus(mView.findFocus(), hasWindowFocus, - mWindowAttributes); + mImeFocusController.onPostWindowFocus(mView != null ? mView.findFocus() : null, + hasWindowFocus, mWindowAttributes); if (hasWindowFocus) { // Clear the forward bit. We can just do this directly, since diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 3b8368380dda..9d66a21848db 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -199,7 +199,7 @@ import java.util.List; * <b>Window state changed</b> - represents the event of a change to a section of * the user interface that is visually distinct. Should be sent from either the * root view of a window or from a view that is marked as a pane - * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Not that changes + * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Note that changes * to true windows are represented by {@link #TYPE_WINDOWS_CHANGED}.</br> * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br> * <em>Properties:</em></br> diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index deed219135ad..22b8ffbd28e3 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -11009,12 +11009,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener MotionEvent.actionToString(event.getActionMasked()), event.getX(), event.getY()); } - if (!isFromPrimePointer(event, false)) { - return true; - } - final int action = event.getActionMasked(); if (mEditor != null) { + if (!isFromPrimePointer(event, false)) { + return true; + } + mEditor.onTouchEvent(event); if (mEditor.mInsertionPointCursorController != null diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java index 9ccb4c172158..9013da36007e 100644 --- a/core/java/android/window/VirtualDisplayTaskEmbedder.java +++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java @@ -19,6 +19,7 @@ package android.window; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.view.Display.INVALID_DISPLAY; import android.app.ActivityManager; @@ -63,6 +64,7 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { private int mDisplayDensityDpi; private final boolean mSingleTaskInstance; private final boolean mUsePublicVirtualDisplay; + private final boolean mUseTrustedDisplay; private VirtualDisplay mVirtualDisplay; private Insets mForwardedInsets; private DisplayMetrics mTmpDisplayMetrics; @@ -77,10 +79,12 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { * only applicable if virtual displays are used */ public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host, - boolean singleTaskInstance, boolean usePublicVirtualDisplay) { + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean useTrustedDisplay) { super(context, host); mSingleTaskInstance = singleTaskInstance; mUsePublicVirtualDisplay = usePublicVirtualDisplay; + mUseTrustedDisplay = useTrustedDisplay; } /** @@ -103,6 +107,9 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { if (mUsePublicVirtualDisplay) { virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_PUBLIC; } + if (mUseTrustedDisplay) { + virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_TRUSTED; + } mVirtualDisplay = displayManager.createVirtualDisplay( DISPLAY_NAME + "@" + System.identityHashCode(this), mHost.getWidth(), diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ac8f9e8424b7..9679a8cdf735 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1761,7 +1761,7 @@ public class ChooserActivity extends ResolverActivity implements case ChooserListAdapter.TARGET_CALLER: case ChooserListAdapter.TARGET_STANDARD: cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; - value -= currentListAdapter.getSelectableServiceTargetCount(); + value -= currentListAdapter.getSurfacedTargetInfo().size(); numCallerProvided = currentListAdapter.getCallerTargetCount(); getChooserActivityLogger().logShareTargetSelected( SELECTION_TYPE_APP, diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index b4cd145ca374..40c21bddf41b 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -428,6 +428,22 @@ public final class SystemUiDeviceConfigFlags { */ public static final String SCREENSHOT_KEYCHORD_DELAY = "screenshot_keychord_delay"; + /** + * (boolean) Whether to use an ML model for the Back Gesture. + */ + public static final String USE_BACK_GESTURE_ML_MODEL = "use_back_gesture_ml_model"; + + /** + * (string) The name of the ML model for Back Gesture. + */ + public static final String BACK_GESTURE_ML_MODEL_NAME = "back_gesture_ml_model_name"; + + /** + * (float) Threshold for Back Gesture ML model prediction. + */ + public static final String BACK_GESTURE_ML_MODEL_THRESHOLD = "back_gesture_ml_model_threshold"; + + private SystemUiDeviceConfigFlags() { } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 046981cf2e8f..d90a0225608d 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -1510,11 +1510,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (drawable != mBackgroundDrawable) { mBackgroundDrawable = drawable; if (mDecor != null) { + mDecor.startChanging(); mDecor.setWindowBackground(drawable); if (mBackgroundFallbackDrawable != null) { mDecor.setBackgroundFallback(drawable != null ? null : mBackgroundFallbackDrawable); } + mDecor.finishChanging(); } } } diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 9ad4cd9e9ae8..b5955c4c46cc 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -249,6 +249,16 @@ static jint CameraMetadata_getEntryCount(JNIEnv *env, jclass thiz, jlong ptr) { return metadata->entryCount(); } +static jlong CameraMetadata_getBufferSize(JNIEnv *env, jclass thiz, jlong ptr) { + ALOGV("%s", __FUNCTION__); + + CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr); + + if (metadata == NULL) return 0; + + return metadata->bufferSize(); +} + // idempotent. calling more than once has no effect. static void CameraMetadata_close(JNIEnv *env, jclass thiz, jlong ptr) { ALOGV("%s", __FUNCTION__); @@ -552,6 +562,9 @@ static const JNINativeMethod gCameraMetadataMethods[] = { { "nativeGetEntryCount", "(J)I", (void*)CameraMetadata_getEntryCount }, + { "nativeGetBufferSize", + "(J)J", + (void*)CameraMetadata_getBufferSize }, { "nativeClose", "(J)V", (void*)CameraMetadata_close }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9c65b04d68a1..79f027662994 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -144,7 +144,7 @@ <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.UUID" /> <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" /> - <protected-broadcast android:name="android.bluetooth.action.ALIAS_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.FOUND" /> <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" /> @@ -4326,6 +4326,10 @@ <permission android:name="android.permission.WRITE_DREAM_STATE" android:protectionLevel="signature|privileged" /> + <!-- @hide Allows applications to read whether ambient display is suppressed. --> + <permission android:name="android.permission.READ_DREAM_SUPPRESSION" + android:protectionLevel="signature" /> + <!-- @SystemApi Allow an application to read and write the cache partition. @hide --> <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index a1db3bc31e09..f49e2ef11ade 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1224,7 +1224,7 @@ <string name="dump_heap_ready_text" msgid="5849618132123045516">"የ<xliff:g id="PROC">%1$s</xliff:g> ሂደት ተራጋፊ ክምር ለማጋራት ለእርስዎ ይገኛል። ይጠንቀቁ፦ ይህ ተራጋፊ ክምር ሂደቱ ሊደርስባቸው የሚችለው ማንኛውም የግል መረጃ ሊኖረው ይችላል፣ ይህ እርስዎ የተየቧቸውን ነገሮች ሊያካትት ይችላል።"</string> <string name="sendText" msgid="493003724401350724">"ለፅሁፍ ድርጊት ምረጥ"</string> <string name="volume_ringtone" msgid="134784084629229029">"የስልክ ጥሪ ድምፅ"</string> - <string name="volume_music" msgid="7727274216734955095">"የማህደረ መረጃ ድምጽ መጠን"</string> + <string name="volume_music" msgid="7727274216734955095">" ማህደረ መረጃ ክፍልፍል"</string> <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"በብሉቱዝ በኩል ማጫወት"</string> <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"የፀጥታ የስልክ የደውል ድምፅ ተዘጋጅቷል"</string> <string name="volume_call" msgid="7625321655265747433">"የጥሪ ላይ ድም ፅ መጨመሪያ/መቀነሻ"</string> @@ -1235,7 +1235,7 @@ <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"የብሉቱዝ ድምፅ መጠን"</string> <string name="volume_icon_description_ringer" msgid="2187800636867423459">"የስልክ ጥሪ ድምፅ መጠን"</string> <string name="volume_icon_description_incall" msgid="4491255105381227919">"የስልክ ጥሪ ድምፅ መጠን"</string> - <string name="volume_icon_description_media" msgid="4997633254078171233">"የማህደረ መረጃ ድምጽ መጠን"</string> + <string name="volume_icon_description_media" msgid="4997633254078171233">"የማህደረ መረጃ ክፍልፍል"</string> <string name="volume_icon_description_notification" msgid="579091344110747279">"የማሳወቂያ ክፍልፍል"</string> <string name="ringtone_default" msgid="9118299121288174597">"ነባሪ የስልክ ላይ ጥሪ"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"ነባሪ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index a65f3a3caf59..73adbd86385f 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -687,7 +687,7 @@ <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Bəzi ekran kilidi funksiyalarını deaktiv edin"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Bəzi ekran funksiyaları istifadəsinin qarşısını alın."</string> <string-array name="phoneTypes"> - <item msgid="8996339953292723951">"Ev"</item> + <item msgid="8996339953292723951">"Əsas səhifə"</item> <item msgid="7740243458912727194">"Mobil"</item> <item msgid="8526146065496663766">"İş"</item> <item msgid="8150904584178569699">"İş Faksı"</item> @@ -697,19 +697,19 @@ <item msgid="6216981255272016212">"Şəxsi"</item> </string-array> <string-array name="emailAddressTypes"> - <item msgid="7786349763648997741">"Ev"</item> + <item msgid="7786349763648997741">"Ana səhifə"</item> <item msgid="435564470865989199">"İş"</item> <item msgid="4199433197875490373">"Digər"</item> <item msgid="3233938986670468328">"Fərdi"</item> </string-array> <string-array name="postalAddressTypes"> - <item msgid="3861463339764243038">"Ev"</item> + <item msgid="3861463339764243038">"Əsas səhifə"</item> <item msgid="5472578890164979109">"İş"</item> <item msgid="5718921296646594739">"Digər"</item> <item msgid="5523122236731783179">"Düzənləyin"</item> </string-array> <string-array name="imAddressTypes"> - <item msgid="588088543406993772">"Ev"</item> + <item msgid="588088543406993772">"Əsas səhifə"</item> <item msgid="5503060422020476757">"İş"</item> <item msgid="2530391194653760297">"Digər"</item> <item msgid="7640927178025203330">"Fərdi"</item> @@ -755,16 +755,16 @@ <string name="eventTypeAnniversary" msgid="4684702412407916888">"İldönümü"</string> <string name="eventTypeOther" msgid="530671238533887997">"Digər"</string> <string name="emailTypeCustom" msgid="1809435350482181786">"Fərdi"</string> - <string name="emailTypeHome" msgid="1597116303154775999">"Şəxsi"</string> + <string name="emailTypeHome" msgid="1597116303154775999">"Əsas səhifə"</string> <string name="emailTypeWork" msgid="2020095414401882111">"İş"</string> <string name="emailTypeOther" msgid="5131130857030897465">"Digər"</string> <string name="emailTypeMobile" msgid="787155077375364230">"Mobil"</string> <string name="postalTypeCustom" msgid="5645590470242939129">"Fərdi"</string> - <string name="postalTypeHome" msgid="7562272480949727912">"Ev"</string> + <string name="postalTypeHome" msgid="7562272480949727912">"Əsas səhifə"</string> <string name="postalTypeWork" msgid="8553425424652012826">"İş"</string> <string name="postalTypeOther" msgid="7094245413678857420">"Digər"</string> <string name="imTypeCustom" msgid="5653384545085765570">"Fərdi"</string> - <string name="imTypeHome" msgid="6996507981044278216">"Ev"</string> + <string name="imTypeHome" msgid="6996507981044278216">"Ana səhifə"</string> <string name="imTypeWork" msgid="2099668940169903123">"İş"</string> <string name="imTypeOther" msgid="8068447383276219810">"Digər"</string> <string name="imProtocolCustom" msgid="4437878287653764692">"Şəxsi"</string> @@ -796,7 +796,7 @@ <string name="relationTypeSister" msgid="3721676005094140671">"Bacı"</string> <string name="relationTypeSpouse" msgid="6916682664436031703">"Həyat yoldaşı"</string> <string name="sipAddressTypeCustom" msgid="6283889809842649336">"Fərdi"</string> - <string name="sipAddressTypeHome" msgid="5918441930656878367">"Ev"</string> + <string name="sipAddressTypeHome" msgid="5918441930656878367">"Əsas səhifə"</string> <string name="sipAddressTypeWork" msgid="7873967986701216770">"İş"</string> <string name="sipAddressTypeOther" msgid="6317012577345187275">"Digər"</string> <string name="quick_contacts_not_available" msgid="1262709196045052223">"Bu kontakta baxmaq üçün heç bir tətbiq tapılmadı."</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 70a191e29ff1..454a21e1f719 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -98,9 +98,9 @@ <string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi-тэлефанія"</string> <string name="notification_channel_sim" msgid="5098802350325677490">"Статус SIM-карты"</string> <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"Стан SIM-карты з высокім прыярытэтам"</string> - <string name="peerTtyModeFull" msgid="337553730440832160">"Аднарангавая прылада запытала рэжым поўнафункцыянальнага TTY"</string> - <string name="peerTtyModeHco" msgid="5626377160840915617">"Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка"</string> - <string name="peerTtyModeVco" msgid="572208600818270944">"Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка"</string> + <string name="peerTtyModeFull" msgid="337553730440832160">"Аднарангавая прылада запытала рэжым TTY FULL"</string> + <string name="peerTtyModeHco" msgid="5626377160840915617">"Аднарангавая прылада запытала рэжым TTY НСО"</string> + <string name="peerTtyModeVco" msgid="572208600818270944">"Аднарангавая прылада запытала рэжым TTY VCO"</string> <string name="peerTtyModeOff" msgid="2420380956369226583">"Аднарангавая прылада запытала рэжым TTY OFF"</string> <string name="serviceClassVoice" msgid="2065556932043454987">"Голас"</string> <string name="serviceClassData" msgid="4148080018967300248">"Дадзеныя"</string> @@ -703,10 +703,10 @@ <item msgid="6216981255272016212">"Асаблівы"</item> </string-array> <string-array name="emailAddressTypes"> - <item msgid="7786349763648997741">"Асабістая"</item> - <item msgid="435564470865989199">"Працоўная"</item> - <item msgid="4199433197875490373">"Іншая"</item> - <item msgid="3233938986670468328">"Карыстальніцкая"</item> + <item msgid="7786349763648997741">"Хатні"</item> + <item msgid="435564470865989199">"Працоўны"</item> + <item msgid="4199433197875490373">"Іншы"</item> + <item msgid="3233938986670468328">"Карыстальніцкі"</item> </string-array> <string-array name="postalAddressTypes"> <item msgid="3861463339764243038">"На Галоўную старонку"</item> @@ -756,14 +756,14 @@ <string name="phoneTypeWorkPager" msgid="3748332310638505234">"Працоўны пэйджар"</string> <string name="phoneTypeAssistant" msgid="757550783842231039">"Асістэнт"</string> <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string> - <string name="eventTypeCustom" msgid="3257367158986466481">"Карыстальніцкае"</string> + <string name="eventTypeCustom" msgid="3257367158986466481">"Карыстальніцкі"</string> <string name="eventTypeBirthday" msgid="7770026752793912283">"Дзень нараджэння"</string> <string name="eventTypeAnniversary" msgid="4684702412407916888">"Гадавіна"</string> <string name="eventTypeOther" msgid="530671238533887997">"Іншае"</string> - <string name="emailTypeCustom" msgid="1809435350482181786">"Карыстальніцкая"</string> + <string name="emailTypeCustom" msgid="1809435350482181786">"Карыстальніцкі"</string> <string name="emailTypeHome" msgid="1597116303154775999">"Хатні"</string> - <string name="emailTypeWork" msgid="2020095414401882111">"Працоўная"</string> - <string name="emailTypeOther" msgid="5131130857030897465">"Іншая"</string> + <string name="emailTypeWork" msgid="2020095414401882111">"Працоўны"</string> + <string name="emailTypeOther" msgid="5131130857030897465">"Іншы"</string> <string name="emailTypeMobile" msgid="787155077375364230">"Мабільны"</string> <string name="postalTypeCustom" msgid="5645590470242939129">"Карыстальніцкі"</string> <string name="postalTypeHome" msgid="7562272480949727912">"Хатні"</string> @@ -786,19 +786,19 @@ <string name="orgTypeWork" msgid="8684458700669564172">"Працоўная"</string> <string name="orgTypeOther" msgid="5450675258408005553">"Іншая"</string> <string name="orgTypeCustom" msgid="1126322047677329218">"Карыстальніцкі"</string> - <string name="relationTypeCustom" msgid="282938315217441351">"Карыстальніцкае"</string> + <string name="relationTypeCustom" msgid="282938315217441351">"Карыстальніцкі"</string> <string name="relationTypeAssistant" msgid="4057605157116589315">"Памочнік"</string> <string name="relationTypeBrother" msgid="7141662427379247820">"Брат"</string> <string name="relationTypeChild" msgid="9076258911292693601">"Дзіця"</string> - <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"Сужыцель/сужыцелька"</string> + <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"Унутраны Партнёр"</string> <string name="relationTypeFather" msgid="3856225062864790596">"Бацька"</string> <string name="relationTypeFriend" msgid="3192092625893980574">"Сябар/сяброўка"</string> <string name="relationTypeManager" msgid="2272860813153171857">"Кіраўнік"</string> <string name="relationTypeMother" msgid="2331762740982699460">"Маці"</string> - <string name="relationTypeParent" msgid="4177920938333039882">"Бацька/маці"</string> + <string name="relationTypeParent" msgid="4177920938333039882">"Бацька"</string> <string name="relationTypePartner" msgid="4018017075116766194">"Партнёр"</string> - <string name="relationTypeReferredBy" msgid="5285082289602849400">"Рэкамендацыя"</string> - <string name="relationTypeRelative" msgid="3396498519818009134">"Радня"</string> + <string name="relationTypeReferredBy" msgid="5285082289602849400">"Запрошаны"</string> + <string name="relationTypeRelative" msgid="3396498519818009134">"Адносны"</string> <string name="relationTypeSister" msgid="3721676005094140671">"Сястра"</string> <string name="relationTypeSpouse" msgid="6916682664436031703">"Муж/жонка"</string> <string name="sipAddressTypeCustom" msgid="6283889809842649336">"Карыстальніцкі"</string> @@ -953,7 +953,7 @@ <string name="permlab_addVoicemail" msgid="4770245808840814471">"дадаць галасавое паведамленне"</string> <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Дазваляе прыкладанням дадаваць паведамленні ў вашу скрыню галасавой пошты."</string> <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"змяніць дазволы геапазіцыянавання для браўзэра"</string> - <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Дазваляе праграме змяняць дазволы геалакацыі браўзера. Шкодныя праграмы могуць выкарыстоўваць гэта, каб адпраўляць даныя аб месцазнаходжанні на любыя вэб-сайты."</string> + <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам."</string> <string name="save_password_message" msgid="2146409467245462965">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string> <string name="save_password_notnow" msgid="2878327088951240061">"Не зараз"</string> <string name="save_password_remember" msgid="6490888932657708341">"Запомніць"</string> @@ -1351,8 +1351,8 @@ <string name="usb_tether_notification_title" msgid="8828527870612663771">"Рэжым USB-мадэма"</string> <string name="usb_midi_notification_title" msgid="7404506788950595557">"MIDI праз USB"</string> <string name="usb_accessory_notification_title" msgid="1385394660861956980">"USB-прылада падключана"</string> - <string name="usb_notification_message" msgid="4715163067192110676">"Дакраніцеся, каб убачыць іншыя параметры."</string> - <string name="usb_power_notification_message" msgid="7284765627437897702">"Падключаная прылада зараджаецца. Дакраніцеся, каб убачыць іншыя параметры."</string> + <string name="usb_notification_message" msgid="4715163067192110676">"Дакраніцеся, каб атрымаць іншыя параметры."</string> + <string name="usb_power_notification_message" msgid="7284765627437897702">"Зарадка падключанай прылады. Націсніце, каб убачыць іншыя параметры."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Выяўлены аксесуар аналагавага аўдыя"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Далучаная прылада не сумяшчальная з гэтым тэлефонам. Націсніце, каб даведацца больш."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"Адладка па USB падключана"</string> @@ -1539,7 +1539,7 @@ <string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Не атрымалася запусціць <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Апублікаваць з дапамогай"</string> <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Адправiць з дапамогай прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> - <string name="content_description_sliding_handle" msgid="982510275422590757">"Маркер для перасоўвання. Дакраніцеся і ўтрымлівайце."</string> + <string name="content_description_sliding_handle" msgid="982510275422590757">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string> <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Прагартайце, каб разблакаваць."</string> <string name="action_bar_home_description" msgid="1501655419158631974">"Перайсці да пачатковай старонкі"</string> <string name="action_bar_up_description" msgid="6611579697195026932">"Перайсці ўверх"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 413feb322fa1..fd53b69a61a1 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -575,7 +575,7 @@ <string name="face_acquired_not_detected" msgid="2945945257956443257">"Postavite lice direktno ispred telefona"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše pokreta. Držite telefon mirno."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte lice."</string> - <string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string> + <string name="face_acquired_too_different" msgid="4699657338753282542">"Nije više moguće prepoznati lice. Pokušajte opet."</string> <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string> <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string> <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje zakrenite glavu."</string> @@ -956,7 +956,7 @@ <string name="save_password_remember" msgid="6490888932657708341">"Zapamti"</string> <string name="save_password_never" msgid="6776808375903410659">"Nikad"</string> <string name="open_permission_deny" msgid="5136793905306987251">"Nemate odobrenje za otvaranje ove stranice."</string> - <string name="text_copied" msgid="2531420577879738860">"Tekst kopiran u međumemoriju."</string> + <string name="text_copied" msgid="2531420577879738860">"Tekst kopiran u međuspremnik."</string> <string name="copied" msgid="4675902854553014676">"Kopirano"</string> <string name="more_item_label" msgid="7419249600215749115">"Više"</string> <string name="prepend_shortcut_label" msgid="1743716737502867951">"Meni+"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index df42b35f76b8..fdb8f4584b95 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -974,8 +974,8 @@ <string name="searchview_description_submit" msgid="6771060386117334686">"Envia la consulta"</string> <string name="searchview_description_voice" msgid="42360159504884679">"Cerca per veu"</string> <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Vols activar l\'exploració tàctil?"</string> - <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interaccionar amb la tauleta."</string> - <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interaccionar amb el telèfon."</string> + <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interactuar amb la tauleta."</string> + <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interactuar amb el telèfon."</string> <string name="oneMonthDurationPast" msgid="4538030857114635777">"Fa 1 mes"</string> <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Fa més d\'1 mes"</string> <plurals name="last_num_days" formatted="false" msgid="687443109145393632"> @@ -1229,7 +1229,7 @@ <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"S\'ha establert el so de silenci"</string> <string name="volume_call" msgid="7625321655265747433">"Volum en trucada"</string> <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volum en trucada per Bluetooth"</string> - <string name="volume_alarm" msgid="4486241060751798448">"Volum d\'alarma"</string> + <string name="volume_alarm" msgid="4486241060751798448">"Volum de l\'alarma"</string> <string name="volume_notification" msgid="6864412249031660057">"Volum de notificacions"</string> <string name="volume_unknown" msgid="4041914008166576293">"Volum"</string> <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Volum del Bluetooth"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 9e35f28f9133..4ff597577be6 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1126,8 +1126,8 @@ <string name="loading" msgid="3138021523725055037">"Loading…"</string> <string name="capital_on" msgid="2770685323900821829">"ON"</string> <string name="capital_off" msgid="7443704171014626777">"OFF"</string> - <string name="checked" msgid="9179896827054513119">"checked"</string> - <string name="not_checked" msgid="7972320087569023342">"not checked"</string> + <string name="checked" msgid="9179896827054513119">"ticked"</string> + <string name="not_checked" msgid="7972320087569023342">"not ticked"</string> <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string> @@ -1992,7 +1992,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> spreadsheet"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentation"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> presentation"</string> - <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth will stay on in Airplane mode"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth will stay on during aeroplane mode"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Loading"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> files</item> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 3ecfd911eaa2..5db4f42a9a22 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -315,7 +315,7 @@ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Realizar gestos"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string> - <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos de huella digital"</string> + <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos de huellas digitales"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Puede capturar los gestos realizados en el sensor de huellas digitales del dispositivo."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Hacer captura de pantalla"</string> <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Puede hacer capturas de la pantalla."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index cdb3e3b9e700..5ee67d95a418 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -292,7 +292,7 @@ <string name="permgrouplab_sms" msgid="795737735126084874">"Tekstiviestit"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"lähettää ja tarkastella tekstiviestejä"</string> <string name="permgrouplab_storage" msgid="1938416135375282333">"Tiedostot ja media"</string> - <string name="permgroupdesc_storage" msgid="6351503740613026600">"käyttää laitteellesi tallennettuja kuvia, mediatiedostoja ja muita tiedostoja"</string> + <string name="permgroupdesc_storage" msgid="6351503740613026600">"käyttää laitteellesi tallennettuja valokuvia, mediatiedostoja ja muita tiedostoja"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofoni"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"tallentaa ääntä"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Liikkuminen"</string> @@ -1886,7 +1886,7 @@ <string name="app_category_game" msgid="4534216074910244790">"Pelit"</string> <string name="app_category_audio" msgid="8296029904794676222">"Musiikki ja audio"</string> <string name="app_category_video" msgid="2590183854839565814">"Elokuvat ja videot"</string> - <string name="app_category_image" msgid="7307840291864213007">"Kuvat ja kuvat"</string> + <string name="app_category_image" msgid="7307840291864213007">"Kuvat ja valokuvat"</string> <string name="app_category_social" msgid="2278269325488344054">"Some ja viestintä"</string> <string name="app_category_news" msgid="1172762719574964544">"Uutiset ja lehdet"</string> <string name="app_category_maps" msgid="6395725487922533156">"Kartat ja navigointi"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 5f84c120acd7..9d2e267472e3 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -315,7 +315,7 @@ <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Contrôle le niveau de zoom et le positionnement de l\'écran."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Effectuer des gestes"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes."</string> - <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestes d\'empreinte digitale"</string> + <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestes avec l\'empreinte digitale"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Peut enregistrer des gestes effectués sur le lecteur d\'empreinte digitale de l\'appareil."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Prendre une capture d\'écran"</string> <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Peut prendre des captures d\'écran."</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 3256be60b29c..0170f1659b30 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -835,7 +835,7 @@ <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string> <string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproducir"</string> <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Deter"</string> - <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string> + <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Rebobinar"</string> <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avance rápido"</string> <string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emerxencia"</string> <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Bloqueada pola rede"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index fa5284f79d5c..8b0b37448dec 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1146,7 +1146,7 @@ <string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"ઍક્સેસ આપો"</string> <string name="whichEditApplication" msgid="6191568491456092812">"આનાથી સંપાદિત કરો"</string> <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$s સાથે સંપાદિત કરો"</string> - <string name="whichEditApplicationLabel" msgid="1463288652070140285">"ફેરફાર કરો"</string> + <string name="whichEditApplicationLabel" msgid="1463288652070140285">"સંપાદિત કરો"</string> <string name="whichSendApplication" msgid="4143847974460792029">"શેર કરો"</string> <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$s સાથે શેર કરો"</string> <string name="whichSendApplicationLabel" msgid="7467813004769188515">"શેર કરો"</string> @@ -1232,7 +1232,7 @@ <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"સાઇલેન્ટ રિંગટોન સેટ કરી"</string> <string name="volume_call" msgid="7625321655265747433">"ઇન-કૉલ વૉલ્યૂમ"</string> <string name="volume_bluetooth_call" msgid="2930204618610115061">"બ્લૂટૂથ ઇન-કૉલ વૉલ્યૂમ"</string> - <string name="volume_alarm" msgid="4486241060751798448">"અલાર્મ વૉલ્યૂમ"</string> + <string name="volume_alarm" msgid="4486241060751798448">"એલાર્મ વૉલ્યૂમ"</string> <string name="volume_notification" msgid="6864412249031660057">"સૂચના વૉલ્યૂમ"</string> <string name="volume_unknown" msgid="4041914008166576293">"વૉલ્યૂમ"</string> <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"બ્લૂટૂથ વૉલ્યૂમ"</string> @@ -1513,7 +1513,7 @@ <string name="storage_usb_drive" msgid="448030813201444573">"USB ડ્રાઇવ"</string> <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string> <string name="storage_usb" msgid="2391213347883616886">"USB સ્ટોરેજ"</string> - <string name="extract_edit_menu_button" msgid="63954536535863040">"ફેરફાર કરો"</string> + <string name="extract_edit_menu_button" msgid="63954536535863040">"સંપાદિત કરો"</string> <string name="data_usage_warning_title" msgid="9034893717078325845">"ડેટા ચેતવણી"</string> <string name="data_usage_warning_body" msgid="1669325367188029454">"તમે <xliff:g id="APP">%s</xliff:g> ડેટા વાપર્યો છે"</string> <string name="data_usage_mobile_limit_title" msgid="3911447354393775241">"મોબાઇલ ડેટાની મર્યાદા આવી ગઈ"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 5498f81a0dee..bb1ad3230fe7 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -297,7 +297,7 @@ <string name="permgroupdesc_microphone" msgid="1047786732792487722">"hanganyag rögzítése"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Testmozgás"</string> <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"hozzáférés a testmozgási adatokhoz"</string> - <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string> + <string name="permgrouplab_camera" msgid="9090413408963547706">"Fényképezőgép"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"fotók és videók készítése"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Hívásnaplók"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"hívásnapló olvasása és írása"</string> @@ -1872,8 +1872,8 @@ <string name="profile_encrypted_message" msgid="1128512616293157802">"A feloldáshoz koppintson rá"</string> <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Csatlakoztatva a(z) <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> eszközhöz"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Koppintson ide a fájlok megtekintéséhez"</string> - <string name="pin_target" msgid="8036028973110156895">"Kitűzés"</string> - <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> kitűzése"</string> + <string name="pin_target" msgid="8036028973110156895">"Rögzítés"</string> + <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítése"</string> <string name="unpin_target" msgid="3963318576590204447">"Feloldás"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítésének feloldása"</string> <string name="app_info" msgid="6113278084877079851">"Alkalmazásinformáció"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 4c9a720cd8ce..aabfc80fe8fa 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -48,7 +48,7 @@ <string name="invalidPin" msgid="7542498253319440408">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string> <string name="invalidPuk" msgid="8831151490931907083">"Մուտքագրեք PUK, որն 8 կամ ավել թիվ ունի:"</string> <string name="needPuk" msgid="7321876090152422918">"Ձեր SIM քարտը PUK-ով կողպված է: Մուտքագրեք PUK կոդը այն ապակողպելու համար:"</string> - <string name="needPuk2" msgid="7032612093451537186">"Մուտքագրեք PUK2-ը՝ SIM քարտն արգելահանելու համար:"</string> + <string name="needPuk2" msgid="7032612093451537186">"Մուտքագրեք PUK2-ը` SIM քարտն արգելահանելու համար:"</string> <string name="enablePin" msgid="2543771964137091212">"Ձախողվեց: Միացրեք SIM/RUIM կողպումը:"</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="one">Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն արգելափակվելու է:</item> @@ -399,7 +399,7 @@ <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Թույլ է տալիս հավելվածին փոփոխել ձեր պլանշետի զանգերի մատյանը, այդ թվում` մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել` ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string> <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Թույլ է տալիս հավելվածին փոփոխել Android TV սարքի զանգերի մատյանը, այդ թվում՝ մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել՝ ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string> <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Թույլ է տալիս հավելվածին փոփոխել ձեր հեռախոսի զանգերի մատյանը, այդ թվում` մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել` ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string> - <string name="permlab_bodySensors" msgid="3411035315357380862">"օգտագործել մարմնի սենսորները (օրինակ՝ սրտի կծկումների հաճախականության չափիչ)"</string> + <string name="permlab_bodySensors" msgid="3411035315357380862">"օգտագործել մարմնի սենսորները (օրինակ` սրտի կծկումների հաճախականության չափիչ)"</string> <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Հավելվածին թույլ է տալիս մուտք ունենալ սենսորների տվյալներին, որոնք վերահսկում են ձեր ֆիզիկական վիճակը, օրինակ՝ ձեր սրտի զարկերը:"</string> <string name="permlab_readCalendar" msgid="6408654259475396200">"Կարդալ օրացույցի միջոցառումները և տվյալները"</string> <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Այս հավելվածը կարող է կարդալ օրացույցի՝ ձեր պլանշետում պահված բոլոր միջոցառումները, ինչպես նաև հրապարակել կամ պահել ձեր օրացույցի տվյալները:"</string> @@ -418,7 +418,7 @@ <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"տեղադրության մասին տվյալների հասանելիություն ֆոնային ռեժիմում"</string> <string name="permdesc_accessBackgroundLocation" msgid="623676842127558197">"Այս հավելվածը ինչպես ակտիվ, այնպես էլ ֆոնային ռեժիմում աշխատելիս կարող է տեսնել տեղադրության տվյալները։"</string> <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"փոխել ձեր աուդիո կարգավորումները"</string> - <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ՝ ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string> + <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ` ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string> <string name="permlab_recordAudio" msgid="1208457423054219147">"ձայնագրել աուդիո ֆայլ"</string> <string name="permdesc_recordAudio" msgid="3976213377904701093">"Այս հավելվածը ցանկացած պահի կարող է ձայնագրել խոսափողի օգնությամբ:"</string> <string name="permlab_sim_communication" msgid="176788115994050692">"ուղարկել հրամաններ SIM քարտին"</string> @@ -477,7 +477,7 @@ <string name="permlab_changeTetherState" msgid="9079611809931863861">"փոխել միացված կապը"</string> <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Թույլ է տալիս հավելվածին փոխել կապված ցանցի միացման կարգավիճակը:"</string> <string name="permlab_accessWifiState" msgid="5552488500317911052">"դիտել Wi-Fi կապերը"</string> - <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Թույլ է տալիս հավելվածին տեսնել Wi-Fi ցանցի տեղեկություններ, ինչպես օրինակ՝ արդյոք Wi-Fi-ը միացված է, թե` ոչ, և միացված Wi-Fi սարքի անունը:"</string> + <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Թույլ է տալիս հավելվածին տեսնել Wi-Fi ցանցի տեղեկություններ, ինչպես օրինակ` արդյոք Wi-Fi-ը միացված է, թե` ոչ, և միացված Wi-Fi սարքի անունը:"</string> <string name="permlab_changeWifiState" msgid="7947824109713181554">"միանալ Wi-Fi-ին և անջատվել դրանից"</string> <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Թույլ է տալիս հավելվածին միանալ Wi-Fi մուտքի կետերին և անջատվել այդ կետերից, ինչպես նաև կատարել սարքի կարգավորման փոփոխություններ Wi-Fi ցանցերի համար:"</string> <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"թույլատրել Բազմասփյուռ Wi-Fi-ի ընդունումը"</string> @@ -598,7 +598,7 @@ </string-array> <string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"կարդալ համաժամացման կարգավորումները"</string> - <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ՝ այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string> + <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string> <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"համաժամացումը փոխարկել միացվածի և անջատվածի"</string> <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Թույլ է տալիս հավելվածին փոփոխել համաժամացման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամացումը հաշվի հետ:"</string> <string name="permlab_readSyncStats" msgid="3747407238320105332">"կարդալ համաժամացման վիճակագրությունը"</string> @@ -859,7 +859,7 @@ <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Մոռացե՞լ եք սխեման:"</string> <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Հաշվի ապակողպում"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Չափից շատ սխեմայի փորձեր"</string> - <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ապակողպելու համար՝ մուտք գործեք ձեր Google հաշվով:"</string> + <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string> <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Օգտանուն (էլփոստ)"</string> <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Գաղտնաբառ"</string> <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Մուտք գործել"</string> @@ -1404,7 +1404,7 @@ <string name="ime_action_done" msgid="6299921014822891569">"Պատրաստ է"</string> <string name="ime_action_previous" msgid="6548799326860401611">"Նախորդ"</string> <string name="ime_action_default" msgid="8265027027659800121">"Կատարել"</string> - <string name="dial_number_using" msgid="6060769078933953531">"Հավաքել հեռախոսահամարը՝\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string> + <string name="dial_number_using" msgid="6060769078933953531">"Հավաքել հեռախոսահամարը`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string> <string name="create_contact_using" msgid="6200708808003692594">"Ստեղծել կոնտակտ`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string> <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Հետևյալ մեկ կամ ավել հավելվածներ մուտքի թույլտվության հարցում են անում` այժմ և հետագայում ձեր հաշվին մուտք ունենալու համար:"</string> <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Ցանկանու՞մ եք թույլատրել այս հարցումը:"</string> @@ -1471,7 +1471,7 @@ <string name="number_picker_increment_button" msgid="7621013714795186298">"Ավելացնել"</string> <string name="number_picker_decrement_button" msgid="5116948444762708204">"Նվազեցնել"</string> <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> հպեք և պահեք:"</string> - <string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Սահեցրեք վերև՝ ավելացնելու համար, և ներքև՝ նվազեցնելու համար:"</string> + <string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Սահեցրեք վերև` ավելացնելու համար, և ներքև` նվազեցնելու համար:"</string> <string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Աճեցնել րոպեն"</string> <string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Նվազեցնել րոպեն"</string> <string name="time_picker_increment_hour_button" msgid="3063572723197178242">"Աճեցնել ժամը"</string> @@ -1597,7 +1597,7 @@ <string name="kg_invalid_puk" msgid="4809502818518963344">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN ծածկագրերը չեն համընկնում"</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Չափից շատ սխեմայի փորձեր"</string> - <string name="kg_login_instructions" msgid="3619844310339066827">"Ապակողպելու համար՝ մուտք գործեք ձեր Google հաշվով:"</string> + <string name="kg_login_instructions" msgid="3619844310339066827">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Օգտանուն (էլփոստ)"</string> <string name="kg_login_password_hint" msgid="3330530727273164402">"Գաղտնաբառը"</string> <string name="kg_login_submit_button" msgid="893611277617096870">"Մուտք գործել"</string> @@ -1951,7 +1951,7 @@ <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string> <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Չհաջողվեց վերականգնել դյուրանցումը"</string> <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Դյուրանցումն անջատված է"</string> - <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ԱՊԱՏԵՂԱԴՐԵԼ"</string> + <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ՀԵՌԱՑՆԵԼ"</string> <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ԲԱՑԵԼ"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Հայտնաբերվել է վնասաբեր հավելված"</string> <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index c90267ed5a59..7963ba7f67a9 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1239,7 +1239,7 @@ <string name="volume_icon_description_notification" msgid="579091344110747279">"Volume pemberitahuan"</string> <string name="ringtone_default" msgid="9118299121288174597">"Nada dering default"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> - <string name="ringtone_silent" msgid="397111123930141876">"Tidak ada"</string> + <string name="ringtone_silent" msgid="397111123930141876">"Tidak Ada"</string> <string name="ringtone_picker_title" msgid="667342618626068253">"Nada dering"</string> <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Suara alarm"</string> <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Suara notifikasi"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 7d627cce5e1b..50e2e1541ec8 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1974,7 +1974,7 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការជូនដំណឹងព័ត៌មានរបស់មុខងារទម្លាប់"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ថ្មអាចនឹងអស់ មុនពេលសាកថ្មធម្មតា"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការកម្មវិធីសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string> - <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"មុខងារសន្សំថ្ម"</string> + <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"កម្មវិធីសន្សំថ្ម"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"កម្មវិធីសន្សំថ្មត្រូវបានបិទ"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ទូរសព្ទមានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"ថេប្លេតមានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index ae8a7206f23f..a80779cfaca5 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -971,7 +971,7 @@ <string name="searchview_description_search" msgid="1045552007537359343">"Пребарај"</string> <string name="searchview_description_query" msgid="7430242366971716338">"Пребарај барање"</string> <string name="searchview_description_clear" msgid="1989371719192982900">"Исчисти барање"</string> - <string name="searchview_description_submit" msgid="6771060386117334686">"Испрати барање"</string> + <string name="searchview_description_submit" msgid="6771060386117334686">"Поднеси барање"</string> <string name="searchview_description_voice" msgid="42360159504884679">"Гласовно пребарување"</string> <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Овозможи „Истражувај со допир“?"</string> <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со таблетот."</string> @@ -1436,7 +1436,7 @@ <string name="upload_file" msgid="8651942222301634271">"Избери датотека"</string> <string name="no_file_chosen" msgid="4146295695162318057">"Не е избрана датотека"</string> <string name="reset" msgid="3865826612628171429">"Ресетирај"</string> - <string name="submit" msgid="862795280643405865">"Испрати"</string> + <string name="submit" msgid="862795280643405865">"Поднеси"</string> <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликацијата за возење работи"</string> <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Допрете за да излезете од апликацијата за возење."</string> <string name="back_button_label" msgid="4078224038025043387">"Назад"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 376d6b75b291..7145ef3da91a 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1077,7 +1077,7 @@ <string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="1532369154488982046">"Merk alt"</string> <string name="cut" msgid="2561199725874745819">"Klipp ut"</string> - <string name="copy" msgid="5472512047143665218">"Kopiér"</string> + <string name="copy" msgid="5472512047143665218">"Kopier"</string> <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Kunne ikke kopiere til utklippstavlen"</string> <string name="paste" msgid="461843306215520225">"Lim inn"</string> <string name="paste_as_plain_text" msgid="7664800665823182587">"Lim inn som ren tekst"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 9a419a83197f..b5194eb7ba1b 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -882,7 +882,7 @@ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="4729922043778400434">"ਅਣਲਾਕ ਖੇਤਰ ਨਸ਼ਟ ਕੀਤਾ।"</string> <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ਵਿਜੇਟ।"</string> <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"ਉਪਭੋਗਤਾ ਚੋਣਕਾਰ"</string> - <string name="keyguard_accessibility_status" msgid="6792745049712397237">"ਸਥਿਤੀ"</string> + <string name="keyguard_accessibility_status" msgid="6792745049712397237">"ਅਵਸਥਾ"</string> <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"ਕੈਮਰਾ"</string> <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"ਮੀਡੀਆ ਨਿਯੰਤਰਣ"</string> <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"ਵਿਜੇਟ ਨੂੰ ਪੁਨਰ ਤਰਤੀਬ ਦੇਣਾ ਸ਼ੁਰੂ ਹੋਇਆ।"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index c509dc177a1c..244d0e680d18 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1321,7 +1321,7 @@ <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Отмена"</string> <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Запомнить выбор"</string> <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Это можно изменить позже в разделе настроек \"Приложения\"."</string> - <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Разрешать всегда"</string> + <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Всегда разрешать"</string> <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Не разрешать"</string> <string name="sim_removed_title" msgid="5387212933992546283">"SIM-карта удалена"</string> <string name="sim_removed_message" msgid="9051174064474904617">"Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index afc742d64c23..88b62f439ba2 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1802,7 +1802,7 @@ <item quantity="other">I %d tim</item> <item quantity="one">I en 1 tim</item> </plurals> - <string name="zen_mode_until" msgid="2250286190237669079">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> + <string name="zen_mode_until" msgid="2250286190237669079">"Till kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> <string name="zen_mode_alarm" msgid="7046911727540499275">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nästa alarm)"</string> <string name="zen_mode_forever" msgid="740585666364912448">"Tills du stänger av"</string> <string name="zen_mode_forever_dnd" msgid="3423201955704180067">"Tills du inaktiverar Stör ej"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 77c4042d9f00..e94856bb1f53 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -293,7 +293,7 @@ <string name="permgroupdesc_sms" msgid="5726462398070064542">"itume na iangalie SMS"</string> <string name="permgrouplab_storage" msgid="1938416135375282333">"Faili na maudhui"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ifikie picha, maudhui na faili kwenye kifaa chako"</string> - <string name="permgrouplab_microphone" msgid="2480597427667420076">"Maikrofoni"</string> + <string name="permgrouplab_microphone" msgid="2480597427667420076">"Kipokea sauti"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"irekodi sauti"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Shughuli za kimwili"</string> <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ifikie shughuli zako za kimwili"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 33dd373b3fe4..37bb5cd12789 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1116,7 +1116,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="1532369154488982046">"Вибрати все"</string> - <string name="cut" msgid="2561199725874745819">"Вирізати"</string> + <string name="cut" msgid="2561199725874745819">"Виріз."</string> <string name="copy" msgid="5472512047143665218">"Копіювати"</string> <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Не вдалося скопіювати в буфер обміну"</string> <string name="paste" msgid="461843306215520225">"Вставити"</string> @@ -1829,7 +1829,7 @@ <item quantity="other">Протягом %1$d хв (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> </plurals> <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="7725354244196466758"> - <item quantity="one">%1$d година (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> + <item quantity="one">%1$d годину (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> <item quantity="few">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> <item quantity="many">%1$d годин (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> <item quantity="other">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 42a658e50073..a896a65eab08 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4175,6 +4175,35 @@ If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> <integer name="config_defaultRefreshRateInZone">0</integer> + <!-- The display uses different gamma curves for different refresh rates. It's hard for panel + vendor to tune the curves to have exact same brightness for different refresh rate. So + flicker could be observed at switch time. The issue can be observed on the screen with + even full white content at the high brightness. To prevent flickering, we support fixed + refresh rates if the display and ambient brightness are equal to or above the provided + thresholds. You can define multiple threshold levels as higher brightness environments + may have lower display brightness requirements for the flickering is visible. And the + high brightness environment could have higher threshold. + For example, fixed refresh rate if + display brightness >= disp0 && ambient brightness >= amb0 + || display brightness >= disp1 && ambient brightness >= amb1 --> + <integer-array translatable="false" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate"> + <!-- + <item>disp0</item> + <item>disp1</item> + --> + </integer-array> + + <integer-array translatable="false" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate"> + <!-- + <item>amb0</item> + <item>amb1</item> + --> + </integer-array> + + <!-- Default refresh rate in the high zone defined by brightness and ambient thresholds. + If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> + <integer name="config_fixedRefreshRateInHighZone">0</integer> + <!-- The type of the light sensor to be used by the display framework for things like auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> <string name="config_displayLightSensorType" translatable="false" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c505afe0509e..4c255f13ec18 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3790,6 +3790,11 @@ <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> + <!-- For fixed refresh rate displays in high brightness--> + <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" /> + <java-symbol type="array" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate" /> + <java-symbol type="array" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate" /> + <!-- For Auto-Brightness --> <java-symbol type="string" name="config_displayLightSensorType" /> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index b39c89b62eb1..6aa5dfc5a11e 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -129,6 +129,7 @@ <!-- virtual display test permissions --> <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" /> <uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" /> + <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" /> <!-- color extraction test permissions --> <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java index daf613976358..0f6284d22d10 100644 --- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java +++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java @@ -247,6 +247,25 @@ public class VirtualDisplayTest extends AndroidTestCase { assertDisplayUnregistered(display); } + /** + * Ensures that an application can create a trusted virtual display with the permission + * {@code ADD_TRUSTED_DISPLAY}. + */ + public void testTrustedVirtualDisplay() throws Exception { + VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME, + WIDTH, HEIGHT, DENSITY, mSurface, + DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED); + assertNotNull("virtual display must not be null", virtualDisplay); + + Display display = virtualDisplay.getDisplay(); + try { + assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_TRUSTED); + } finally { + virtualDisplay.release(); + } + assertDisplayUnregistered(display); + } + private void assertDisplayRegistered(Display display, int flags) { assertNotNull("display object must not be null", display); assertTrue("display must be valid", display.isValid()); diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index e5492714b29f..3c990abaec87 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -163,3 +163,10 @@ prebuilt_etc { src: "com.android.car.ui.paintbooth.xml", filename_from_src: true, } + +prebuilt_etc { + name: "allowed_privapp_com.android.carshell", + sub_dir: "permissions", + src: "com.android.car.shell.xml", + filename_from_src: true, +} diff --git a/data/etc/car/com.android.car.shell.xml b/data/etc/car/com.android.car.shell.xml new file mode 100644 index 000000000000..32666c8d9f68 --- /dev/null +++ b/data/etc/car/com.android.car.shell.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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> + <privapp-permissions package="com.android.car.shell"> + <permission name="android.permission.INSTALL_PACKAGES" /> + <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> + </privapp-permissions> +</permissions> diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index 7292e0796bf5..f21e9bff16ec 100644 --- a/data/etc/car/com.google.android.car.kitchensink.xml +++ b/data/etc/car/com.google.android.car.kitchensink.xml @@ -43,5 +43,8 @@ <!-- use for CarServiceTest --> <permission name="android.permission.SET_ACTIVITY_WATCHER"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + + <!-- use for rotary fragment to enable/disable packages related to rotary --> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> </privapp-permissions> </permissions> diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index fe1182ecad4f..e473c55ce010 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -56,5 +56,7 @@ <permission name="android.permission.WRITE_SECURE_SETTINGS"/> <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" /> <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> + <permission name="android.permission.READ_DREAM_STATE"/> + <permission name="android.permission.READ_DREAM_SUPPRESSION"/> </privapp-permissions> </permissions> diff --git a/diff b/diff deleted file mode 100644 index 5c75d88e6789..000000000000 --- a/diff +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -index fc43882..832dc91 100644 ---- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -@@ -67,6 +67,7 @@ import java.util.Arrays; - import java.util.HashSet; - import java.util.List; - import java.util.Set; -+import java.util.NoSuchElementException; - - /** - * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. -@@ -978,7 +979,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ - /* ignore */ - } - if (mService != null) { -- mService.unlinkToDeath(this, 0); -+ try { -+ mService.unlinkToDeath(this, 0); -+ }catch(NoSuchElementException e) { -+ Slog.e(LOG_TAG, "Failed unregistering death link"); -+ } - mService = null; - } - diff --git a/drm/jni/Android.bp b/drm/jni/Android.bp index 1e33f0ea5094..68757d86fb89 100644 --- a/drm/jni/Android.bp +++ b/drm/jni/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { shared_libs: [ "libdrmframework", + "libdrmframeworkcommon", "liblog", "libutils", "libandroid_runtime", diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index bc1301a86455..fe5c1be05927 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -327,7 +327,7 @@ public class Typeface { * 1) Create Typeface from ttf file. * <pre> * <code> - * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf"); + * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf"); * Typeface typeface = builder.build(); * </code> * </pre> @@ -335,7 +335,7 @@ public class Typeface { * 2) Create Typeface from ttc file in assets directory. * <pre> * <code> - * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc"); + * Typeface.Builder builder = new Typeface.Builder(getAssets(), "your_font_file.ttc"); * builder.setTtcIndex(2); // Set index of font collection. * Typeface typeface = builder.build(); * </code> @@ -344,7 +344,7 @@ public class Typeface { * 3) Create Typeface with variation settings. * <pre> * <code> - * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf"); + * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf"); * builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1"); * builder.setWeight(700); // Tell the system that this is a bold font. * builder.setItalic(true); // Tell the system that this is an italic style font. diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml index 5aab0a172b99..f43f02dfcc8c 100644 --- a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml +++ b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml @@ -45,14 +45,13 @@ app:layout_constraintBottom_toBottomOf="@+id/gradient_edge" app:layout_constraintTop_toTopOf="parent"/> - <FrameLayout + <com.android.car.notification.headsup.HeadsUpContainerView android:id="@+id/headsup_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/headsup_notification_top_margin" app:layout_constraintEnd_toStartOf="parent" app:layout_constraintStart_toEndOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - /> + app:layout_constraintBottom_toBottomOf="parent"/> -</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/CarSystemUI/res/values-af/strings.xml b/packages/CarSystemUI/res/values-af/strings.xml deleted file mode 100644 index 2ab3aa44a86c..000000000000 --- a/packages/CarSystemUI/res/values-af/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Stemherkenning nou deur gekoppelde Bluetooth-toestel hanteer"</string> - <string name="car_guest" msgid="318393171202663722">"Gas"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gas"</string> - <string name="car_add_user" msgid="4067337059622483269">"Voeg gebruiker by"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nuwe gebruiker"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Enige gebruiker kan programme vir al die ander gebruikers opdateer."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Laai tans"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Laai tans gebruiker (van <xliff:g id="FROM_USER">%1$d</xliff:g> na <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-am/strings.xml b/packages/CarSystemUI/res/values-am/strings.xml deleted file mode 100644 index d5b580e3dd9d..000000000000 --- a/packages/CarSystemUI/res/values-am/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ዝቅተኛ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ከፍተኛ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"የድምፅ ለይቶ ማወቅ አሁን በተገናኘ የብሉቱዝ መሣሪያ ይስተናገዳል"</string> - <string name="car_guest" msgid="318393171202663722">"እንግዳ"</string> - <string name="start_guest_session" msgid="497784785761754874">"እንግዳ"</string> - <string name="car_add_user" msgid="4067337059622483269">"ተጠቃሚ አክል"</string> - <string name="car_new_user" msgid="6637442369728092473">"አዲስ ተጠቃሚ"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሳቸውን ቦታ ማቀናበር አለባቸው።"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ማዘመን ይችላል።"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"በመጫን ላይ"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ተጠቃሚን (ከ<xliff:g id="FROM_USER">%1$d</xliff:g> ወደ <xliff:g id="TO_USER">%2$d</xliff:g>) በመጫን ላይ"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ar/strings.xml b/packages/CarSystemUI/res/values-ar/strings.xml deleted file mode 100644 index 09b302d85eab..000000000000 --- a/packages/CarSystemUI/res/values-ar/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"حد أدنى"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"حد أقصى"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"تتم معالجة التعرّف على الصوت الآن من خلال جهاز بلوتوث متصل."</string> - <string name="car_guest" msgid="318393171202663722">"ضيف"</string> - <string name="start_guest_session" msgid="497784785761754874">"ضيف"</string> - <string name="car_add_user" msgid="4067337059622483269">"إضافة مستخدم"</string> - <string name="car_new_user" msgid="6637442369728092473">"مستخدم جديد"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"عند إضافة مستخدم جديد، على هذا المستخدم إعداد مساحته."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"يمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"جارٍ التحميل"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"جارٍ تحميل الملف الشخصي الجديد للمستخدم (من <xliff:g id="FROM_USER">%1$d</xliff:g> إلى <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-as/strings.xml b/packages/CarSystemUI/res/values-as/strings.xml deleted file mode 100644 index a8aa74d8c7a4..000000000000 --- a/packages/CarSystemUI/res/values-as/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"সর্বনিম্ন"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"সৰ্বাধিক"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"কণ্ঠস্বৰৰ চিনাক্তকৰণ এতিয়া সংযুক্ত ব্লুটুথ ডিভাইচে নিয়ন্ত্ৰণ কৰে"</string> - <string name="car_guest" msgid="318393171202663722">"অতিথি"</string> - <string name="start_guest_session" msgid="497784785761754874">"অতিথি"</string> - <string name="car_add_user" msgid="4067337059622483269">"ব্যৱহাৰকাৰী যোগ দিয়ক"</string> - <string name="car_new_user" msgid="6637442369728092473">"নতুন ব্যৱহাৰকাৰী"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰীক যোগ কৰে, তেতিয়া তেওঁ নিজৰ ঠাই ছেট আপ কৰাটো প্ৰয়োজন হয়।"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"যিকোনো ব্যৱহাৰকাৰীয়ে অন্য ব্যৱহাৰকাৰীৰ বাবে এপ্সমূহ আপডে’ট কৰিব পাৰে।"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ল’ড হৈ আছে"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ব্যৱহাৰকাৰী ল’ড হৈ আছে (<xliff:g id="FROM_USER">%1$d</xliff:g>ৰ পৰা to <xliff:g id="TO_USER">%2$d</xliff:g>লৈ)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-az/strings.xml b/packages/CarSystemUI/res/values-az/strings.xml deleted file mode 100644 index 97facc27be68..000000000000 --- a/packages/CarSystemUI/res/values-az/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Səs tanınması qoşulmuş Bluetooth cihazı ilə icra edilir"</string> - <string name="car_guest" msgid="318393171202663722">"Qonaq"</string> - <string name="start_guest_session" msgid="497784785761754874">"Qonaq"</string> - <string name="car_add_user" msgid="4067337059622483269">"İstifadəçi əlavə edin"</string> - <string name="car_new_user" msgid="6637442369728092473">"Yeni İstifadəçi"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yeni istifadəçi əlavə etdiyinizdə həmin şəxs öz yerini təyin etməlidir."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"İstənilən istifadəçi digər bütün istifadəçilər üçün tətbiqləri güncəlləyə bilər."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Yüklənir"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"İstifadəçi yüklənir (<xliff:g id="FROM_USER">%1$d</xliff:g>-<xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml b/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml deleted file mode 100644 index ec310be7a4d8..000000000000 --- a/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa sada upravlja povezani Bluetooth uređaj"</string> - <string name="car_guest" msgid="318393171202663722">"Gost"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gost"</string> - <string name="car_add_user" msgid="4067337059622483269">"Dodaj korisnika"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Svaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Učitava se"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Profil korisnika se učitava (iz<xliff:g id="FROM_USER">%1$d</xliff:g> u <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-be/strings.xml b/packages/CarSystemUI/res/values-be/strings.xml deleted file mode 100644 index 17fc58451464..000000000000 --- a/packages/CarSystemUI/res/values-be/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мін"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Распазнаванне голасу выконвае падключаная прылада Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Госць"</string> - <string name="start_guest_session" msgid="497784785761754874">"Госць"</string> - <string name="car_add_user" msgid="4067337059622483269">"Дадаць карыстальніка"</string> - <string name="car_new_user" msgid="6637442369728092473">"Новы карыстальнік"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Калі вы дадаяце новага карыстальніка, яму трэба наладзіць свой профіль."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Кожны карыстальнік прылады можа абнаўляць праграмы для ўсіх іншых карыстальнікаў."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Ідзе загрузка"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ідзе загрузка профілю карыстальніка (ад <xliff:g id="FROM_USER">%1$d</xliff:g> да <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-bg/strings.xml b/packages/CarSystemUI/res/values-bg/strings.xml deleted file mode 100644 index ae2db2d08f25..000000000000 --- a/packages/CarSystemUI/res/values-bg/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Гл. разпознаване се обработва от свързаното у-во с Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Гост"</string> - <string name="start_guest_session" msgid="497784785761754874">"Гост"</string> - <string name="car_add_user" msgid="4067337059622483269">"Добавяне на потребител"</string> - <string name="car_new_user" msgid="6637442369728092473">"Нов потребител"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Когато добавите нов потребител, той трябва да настрои работната си област."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Всеки потребител може да актуализира приложенията за всички останали потребители."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Зарежда се"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Потребителят се зарежда (от <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-bn/strings.xml b/packages/CarSystemUI/res/values-bn/strings.xml deleted file mode 100644 index 9a01fad952eb..000000000000 --- a/packages/CarSystemUI/res/values-bn/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"সর্বনিম্ন"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"সর্বাধিক"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"কানেক্ট করা ব্লুটুথ ডিভাইস এখন ভয়েস শনাক্তকরণ ম্যানেজ করছে"</string> - <string name="car_guest" msgid="318393171202663722">"অতিথি"</string> - <string name="start_guest_session" msgid="497784785761754874">"অতিথি"</string> - <string name="car_add_user" msgid="4067337059622483269">"ব্যবহারকারীকে যোগ করুন"</string> - <string name="car_new_user" msgid="6637442369728092473">"নতুন ব্যবহারকারী"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"নতুন ব্যবহারকারী যোগ করলে, তার স্পেস তাকে সেট-আপ করে নিতে হবে।"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"যেকোনও ব্যবহারকারী বাকি সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন।"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"লোড হচ্ছে"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ব্যবহারকারীর প্রোফাইল লোড করা হচ্ছে (<xliff:g id="FROM_USER">%1$d</xliff:g> থেকে <xliff:g id="TO_USER">%2$d</xliff:g>-এ)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-bs/strings.xml b/packages/CarSystemUI/res/values-bs/strings.xml deleted file mode 100644 index 5ef9aeba3436..000000000000 --- a/packages/CarSystemUI/res/values-bs/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa sada upravlja povezani Bluetooth uređaj"</string> - <string name="car_guest" msgid="318393171202663722">"Gost"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gost"</string> - <string name="car_add_user" msgid="4067337059622483269">"Dodaj korisnika"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Bilo koji korisnik može ažurirati aplikacije za sve druge korisnike."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Učitavanje"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Učitavanje korisnika (od korisnika <xliff:g id="FROM_USER">%1$d</xliff:g> do korisnika <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ca/strings.xml b/packages/CarSystemUI/res/values-ca/strings.xml deleted file mode 100644 index 375fc5c10baf..000000000000 --- a/packages/CarSystemUI/res/values-ca/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Màx."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconeixement de veu gestionat per disp. Bluetooth connectat"</string> - <string name="car_guest" msgid="318393171202663722">"Convidat"</string> - <string name="start_guest_session" msgid="497784785761754874">"Convidat"</string> - <string name="car_add_user" msgid="4067337059622483269">"Afegeix un usuari"</string> - <string name="car_new_user" msgid="6637442369728092473">"Usuari nou"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Quan s\'afegeix un usuari nou, aquesta persona ha de configurar el seu espai."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"S\'està carregant"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"S\'està carregant l\'usuari (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-cs/strings.xml b/packages/CarSystemUI/res/values-cs/strings.xml deleted file mode 100644 index 8071cef72650..000000000000 --- a/packages/CarSystemUI/res/values-cs/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznávání hlasu teď provádí připojené zařízení Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Host"</string> - <string name="start_guest_session" msgid="497784785761754874">"Host"</string> - <string name="car_add_user" msgid="4067337059622483269">"Přidat uživatele"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nový uživatel"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Každý nově přidaný uživatel si musí nastavit vlastní prostor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Každý uživatel může aktualizovat aplikace všech ostatních uživatelů."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Načítání"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Načítání uživatele (předchozí: <xliff:g id="FROM_USER">%1$d</xliff:g>, následující: <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-da/strings.xml b/packages/CarSystemUI/res/values-da/strings.xml deleted file mode 100644 index b19cdcba5af9..000000000000 --- a/packages/CarSystemUI/res/values-da/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Talegenkendelse sker nu med den forbundne Blutetooth-enhed"</string> - <string name="car_guest" msgid="318393171202663722">"Gæst"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gæst"</string> - <string name="car_add_user" msgid="4067337059622483269">"Tilføj bruger"</string> - <string name="car_new_user" msgid="6637442369728092473">"Ny bruger"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Når du tilføjer en ny bruger, skal vedkommende konfigurere sit område."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Alle brugere kan opdatere apps for alle andre brugere."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Indlæser"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Indlæser bruger (fra <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-de/strings.xml b/packages/CarSystemUI/res/values-de/strings.xml deleted file mode 100644 index 99ba13e4f3f8..000000000000 --- a/packages/CarSystemUI/res/values-de/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Spracherkennung jetzt über das verbundene Bluetooth-Gerät"</string> - <string name="car_guest" msgid="318393171202663722">"Gast"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gast"</string> - <string name="car_add_user" msgid="4067337059622483269">"Nutzer hinzufügen"</string> - <string name="car_new_user" msgid="6637442369728092473">"Neuer Nutzer"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Jeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Wird geladen"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nutzer wird geladen (von <xliff:g id="FROM_USER">%1$d</xliff:g> bis <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-el/strings.xml b/packages/CarSystemUI/res/values-el/strings.xml deleted file mode 100644 index e2d2cec34479..000000000000 --- a/packages/CarSystemUI/res/values-el/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Ελάχ."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Μεγ."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Φωνητική αναγνωση από συνδεδεμένη συσκευή Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Επισκέπτης"</string> - <string name="start_guest_session" msgid="497784785761754874">"Επισκέπτης"</string> - <string name="car_add_user" msgid="4067337059622483269">"Προσθήκη χρήστη"</string> - <string name="car_new_user" msgid="6637442369728092473">"Νέος χρήστης"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Οποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Φόρτωση"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Φόρτωση χρήστη (από <xliff:g id="FROM_USER">%1$d</xliff:g> έως <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-en-rAU/strings.xml b/packages/CarSystemUI/res/values-en-rAU/strings.xml deleted file mode 100644 index b8bf9906916d..000000000000 --- a/packages/CarSystemUI/res/values-en-rAU/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string> - <string name="car_guest" msgid="318393171202663722">"Guest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Guest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Add user"</string> - <string name="car_new_user" msgid="6637442369728092473">"New user"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-en-rCA/strings.xml b/packages/CarSystemUI/res/values-en-rCA/strings.xml deleted file mode 100644 index b8bf9906916d..000000000000 --- a/packages/CarSystemUI/res/values-en-rCA/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string> - <string name="car_guest" msgid="318393171202663722">"Guest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Guest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Add user"</string> - <string name="car_new_user" msgid="6637442369728092473">"New user"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-en-rGB/strings.xml b/packages/CarSystemUI/res/values-en-rGB/strings.xml deleted file mode 100644 index b8bf9906916d..000000000000 --- a/packages/CarSystemUI/res/values-en-rGB/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string> - <string name="car_guest" msgid="318393171202663722">"Guest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Guest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Add user"</string> - <string name="car_new_user" msgid="6637442369728092473">"New user"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-en-rIN/strings.xml b/packages/CarSystemUI/res/values-en-rIN/strings.xml deleted file mode 100644 index b8bf9906916d..000000000000 --- a/packages/CarSystemUI/res/values-en-rIN/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string> - <string name="car_guest" msgid="318393171202663722">"Guest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Guest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Add user"</string> - <string name="car_new_user" msgid="6637442369728092473">"New user"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-en-rXC/strings.xml b/packages/CarSystemUI/res/values-en-rXC/strings.xml deleted file mode 100644 index 1ffa5ebde689..000000000000 --- a/packages/CarSystemUI/res/values-en-rXC/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string> - <string name="car_guest" msgid="318393171202663722">"Guest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Guest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Add User"</string> - <string name="car_new_user" msgid="6637442369728092473">"New User"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-es-rUS/strings.xml b/packages/CarSystemUI/res/values-es-rUS/strings.xml deleted file mode 100644 index 027242a536fa..000000000000 --- a/packages/CarSystemUI/res/values-es-rUS/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"El dispositivo Bluetooth administra el reconocimiento de voz"</string> - <string name="car_guest" msgid="318393171202663722">"Invitado"</string> - <string name="start_guest_session" msgid="497784785761754874">"Invitado"</string> - <string name="car_add_user" msgid="4067337059622483269">"Agregar usuario"</string> - <string name="car_new_user" msgid="6637442369728092473">"Usuario nuevo"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cuando agregues un usuario nuevo, esa persona deberá configurar su espacio."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Cualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-es/strings.xml b/packages/CarSystemUI/res/values-es/strings.xml deleted file mode 100644 index fe546051e729..000000000000 --- a/packages/CarSystemUI/res/values-es/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"El dispositivo Bluetooth gestiona el reconocimiento de voz"</string> - <string name="car_guest" msgid="318393171202663722">"Invitado"</string> - <string name="start_guest_session" msgid="497784785761754874">"Invitado"</string> - <string name="car_add_user" msgid="4067337059622483269">"Añadir usuario"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nuevo usuario"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cuando añades un usuario, esa persona debe configurar su espacio."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Cualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-et/strings.xml b/packages/CarSystemUI/res/values-et/strings.xml deleted file mode 100644 index 2fa71a975973..000000000000 --- a/packages/CarSystemUI/res/values-et/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Häältuvastust haldab nüüd ühendatud Bluetoothi seade"</string> - <string name="car_guest" msgid="318393171202663722">"Külaline"</string> - <string name="start_guest_session" msgid="497784785761754874">"Külaline"</string> - <string name="car_add_user" msgid="4067337059622483269">"Lisa kasutaja"</string> - <string name="car_new_user" msgid="6637442369728092473">"Uus kasutaja"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Iga kasutaja saab rakendusi värskendada kõigi teiste kasutajate jaoks."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Laadimine"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Kasutaja laadimine (<xliff:g id="FROM_USER">%1$d</xliff:g> > <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-eu/strings.xml b/packages/CarSystemUI/res/values-eu/strings.xml deleted file mode 100644 index 36bcaae01443..000000000000 --- a/packages/CarSystemUI/res/values-eu/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Konektatutako Bluetooth bidezko gailuak kudeatzen du ahotsa ezagutzeko eginbidea"</string> - <string name="car_guest" msgid="318393171202663722">"Gonbidatua"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gonbidatua"</string> - <string name="car_add_user" msgid="4067337059622483269">"Gehitu erabiltzaile bat"</string> - <string name="car_new_user" msgid="6637442369728092473">"Erabiltzaile berria"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Erabiltzaile bat gehitzen duzunean, bere eremua konfiguratu beharko du."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Edozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Kargatzen"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Erabiltzailea kargatzen (<xliff:g id="FROM_USER">%1$d</xliff:g> izatetik<xliff:g id="TO_USER">%2$d</xliff:g> izatera igaroko da)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-fa/strings.xml b/packages/CarSystemUI/res/values-fa/strings.xml deleted file mode 100644 index 3224899afb90..000000000000 --- a/packages/CarSystemUI/res/values-fa/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"حداقل"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"حداکثر"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"اکنون تشخیص صدا را دستگاه بلوتوث متصل کنترل میکند"</string> - <string name="car_guest" msgid="318393171202663722">"مهمان"</string> - <string name="start_guest_session" msgid="497784785761754874">"مهمان"</string> - <string name="car_add_user" msgid="4067337059622483269">"افزودن کاربر"</string> - <string name="car_new_user" msgid="6637442369728092473">"کاربر جدید"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"وقتی کاربر جدیدی اضافه میکنید، آن فرد باید فضای خود را تنظیم کند."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"هر کاربری میتواند برنامهها را برای همه کاربران دیگر بهروزرسانی کند."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"درحال بارگیری"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"بارگیری کاربر (از <xliff:g id="FROM_USER">%1$d</xliff:g> تا <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-fi/strings.xml b/packages/CarSystemUI/res/values-fi/strings.xml deleted file mode 100644 index 6abf92ffa77a..000000000000 --- a/packages/CarSystemUI/res/values-fi/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Alin"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Ylin"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Äänentunnistus tehdään nyt yhdistetyllä Bluetooth-laitteella"</string> - <string name="car_guest" msgid="318393171202663722">"Vieras"</string> - <string name="start_guest_session" msgid="497784785761754874">"Vieras"</string> - <string name="car_add_user" msgid="4067337059622483269">"Lisää käyttäjä"</string> - <string name="car_new_user" msgid="6637442369728092473">"Uusi käyttäjä"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kun lisäät uuden käyttäjän, hänen on valittava oman tilansa asetukset."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Kaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Ladataan"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ladataan käyttäjäprofiilia (<xliff:g id="FROM_USER">%1$d</xliff:g>–<xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-fr-rCA/strings.xml b/packages/CarSystemUI/res/values-fr-rCA/strings.xml deleted file mode 100644 index 18e68c07d23d..000000000000 --- a/packages/CarSystemUI/res/values-fr-rCA/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"La reconn. voc. est gérée par l\'appareil Bluetooth connecté"</string> - <string name="car_guest" msgid="318393171202663722">"Invité"</string> - <string name="start_guest_session" msgid="497784785761754874">"Invité"</string> - <string name="car_add_user" msgid="4067337059622483269">"Ajouter un utilisateur"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nouvel utilisateur"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Tout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Chargement en cours…"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Chargement de l\'utilisateur (de <xliff:g id="FROM_USER">%1$d</xliff:g> vers <xliff:g id="TO_USER">%2$d</xliff:g>) en cours…"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-fr/strings.xml b/packages/CarSystemUI/res/values-fr/strings.xml deleted file mode 100644 index 954df67d4b74..000000000000 --- a/packages/CarSystemUI/res/values-fr/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"L\'appareil Bluetooth connecté gère la reconnaissance vocale"</string> - <string name="car_guest" msgid="318393171202663722">"Invité"</string> - <string name="start_guest_session" msgid="497784785761754874">"Invité"</string> - <string name="car_add_user" msgid="4067337059622483269">"Ajouter un utilisateur"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nouvel utilisateur"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"N\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Chargement…"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Chargement de l\'utilisateur (de <xliff:g id="FROM_USER">%1$d</xliff:g> à <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-gl/strings.xml b/packages/CarSystemUI/res/values-gl/strings.xml deleted file mode 100644 index 95bfbd30c0b8..000000000000 --- a/packages/CarSystemUI/res/values-gl/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"O dispositivo Bluetooth xestionará o recoñecemento de voz"</string> - <string name="car_guest" msgid="318393171202663722">"Convidado"</string> - <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string> - <string name="car_add_user" msgid="4067337059622483269">"Engadir usuario"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novo usuario"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cando engadas un novo usuario, este deberá configurar o seu espazo."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Calquera usuario pode actualizar as aplicacións para o resto dos usuarios."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (do <xliff:g id="FROM_USER">%1$d</xliff:g> ao <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-gu/strings.xml b/packages/CarSystemUI/res/values-gu/strings.xml deleted file mode 100644 index dec991ce1400..000000000000 --- a/packages/CarSystemUI/res/values-gu/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ન્યૂનતમ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"મહત્તમ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"અવાજની ઓળખ હવે કનેક્ટેડ બ્લૂટૂથ ડિવાઇસ વડે નિયંત્રિત થશે"</string> - <string name="car_guest" msgid="318393171202663722">"અતિથિ"</string> - <string name="start_guest_session" msgid="497784785761754874">"અતિથિ"</string> - <string name="car_add_user" msgid="4067337059622483269">"વપરાશકર્તા ઉમેરો"</string> - <string name="car_new_user" msgid="6637442369728092473">"નવા વપરાશકર્તા"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિએ તેમની સ્પેસ સેટ કરવાની જરૂર રહે છે."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"કોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"લોડ કરી રહ્યાં છીએ"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"વપરાશકર્તાને લોડ કરી રહ્યાં છીએ (<xliff:g id="FROM_USER">%1$d</xliff:g>માંથી <xliff:g id="TO_USER">%2$d</xliff:g>માં)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-hi/strings.xml b/packages/CarSystemUI/res/values-hi/strings.xml deleted file mode 100644 index 89b69608efbe..000000000000 --- a/packages/CarSystemUI/res/values-hi/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"कम से कम"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ज़्यादा से ज़्यादा"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"अब आवाज़ पहचानने का काम, कनेक्ट किए गए ब्लूटूथ डिवाइस करते हैं"</string> - <string name="car_guest" msgid="318393171202663722">"मेहमान प्रोफ़ाइल"</string> - <string name="start_guest_session" msgid="497784785761754874">"मेहमान के तौर पर सेशन शुरू करें"</string> - <string name="car_add_user" msgid="4067337059622483269">"उपयोगकर्ता जोड़ें"</string> - <string name="car_new_user" msgid="6637442369728092473">"नया उपयोगकर्ता"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तब उसे अपनी जगह सेट करनी होती है."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"कोई भी उपयोगकर्ता, बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"लोड हो रही है"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"उपयोगकर्ता को लोड किया जा रहा है (<xliff:g id="FROM_USER">%1$d</xliff:g> से <xliff:g id="TO_USER">%2$d</xliff:g> पर)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-hr/strings.xml b/packages/CarSystemUI/res/values-hr/strings.xml deleted file mode 100644 index 6baec74ddbff..000000000000 --- a/packages/CarSystemUI/res/values-hr/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa rukuje se s povezanog Bluetooth uređaja"</string> - <string name="car_guest" msgid="318393171202663722">"Gost"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gost"</string> - <string name="car_add_user" msgid="4067337059622483269">"Dodajte korisnika"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Svaki korisnik može ažurirati aplikacije za ostale korisnike."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Učitavanje"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Učitavanje korisnika (od <xliff:g id="FROM_USER">%1$d</xliff:g> do <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-hu/strings.xml b/packages/CarSystemUI/res/values-hu/strings.xml deleted file mode 100644 index ffa512c4772a..000000000000 --- a/packages/CarSystemUI/res/values-hu/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"A hangfelismerést a csatlakoztatott Bluetooth-eszköz kezeli"</string> - <string name="car_guest" msgid="318393171202663722">"Vendég"</string> - <string name="start_guest_session" msgid="497784785761754874">"Vendég"</string> - <string name="car_add_user" msgid="4067337059622483269">"Felhasználó hozzáadása"</string> - <string name="car_new_user" msgid="6637442369728092473">"Új felhasználó"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját felületét."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Bármely felhasználó frissítheti az alkalmazásokat az összes felhasználó számára."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Betöltés"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Felhasználó betöltése (<xliff:g id="FROM_USER">%1$d</xliff:g> → <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-hy/strings.xml b/packages/CarSystemUI/res/values-hy/strings.xml deleted file mode 100644 index ee6f74b4e5d8..000000000000 --- a/packages/CarSystemUI/res/values-hy/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Նվազ․"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Առավ․"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Ձայնի ճանաչումը մշակվում է միացված Bluetooth սարքի կողմից"</string> - <string name="car_guest" msgid="318393171202663722">"Հյուր"</string> - <string name="start_guest_session" msgid="497784785761754874">"Հյուրի ռեժիմ"</string> - <string name="car_add_user" msgid="4067337059622483269">"Ավելացնել օգտատեր"</string> - <string name="car_new_user" msgid="6637442369728092473">"Նոր օգտատեր"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Երբ դուք նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը։"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Ցանկացած օգտատեր կարող է թարմացնել հավելվածները բոլոր մյուս հաշիվների համար։"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Բեռնում"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Օգտատերը բեռնվում է (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-in/strings.xml b/packages/CarSystemUI/res/values-in/strings.xml deleted file mode 100644 index 1145dc32dcb0..000000000000 --- a/packages/CarSystemUI/res/values-in/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Pengenalan suara ditangani perangkat Bluetooth terhubung"</string> - <string name="car_guest" msgid="318393171202663722">"Tamu"</string> - <string name="start_guest_session" msgid="497784785761754874">"Tamu"</string> - <string name="car_add_user" msgid="4067337059622483269">"Tambahkan Pengguna"</string> - <string name="car_new_user" msgid="6637442369728092473">"Pengguna Baru"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Jika ditambahkan, pengguna baru harus menyiapkan ruangnya sendiri."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Setiap pengguna dapat mengupdate aplikasi untuk semua pengguna lain."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Memuat"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Memuat pengguna (dari <xliff:g id="FROM_USER">%1$d</xliff:g> menjadi <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-is/strings.xml b/packages/CarSystemUI/res/values-is/strings.xml deleted file mode 100644 index 13e71366ebd3..000000000000 --- a/packages/CarSystemUI/res/values-is/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Lágm."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Hám."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Raddgreiningu er nú stjórnað af tengdu Bluetooth-tæki"</string> - <string name="car_guest" msgid="318393171202663722">"Gestur"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gestur"</string> - <string name="car_add_user" msgid="4067337059622483269">"Bæta notanda við"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nýr notandi"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Þegar þú bætir nýjum notanda við þarf viðkomandi að setja upp sitt eigið svæði."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Allir notendur geta uppfært forrit fyrir alla aðra notendur."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Hleður"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Hleður notanda (frá <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-it/strings.xml b/packages/CarSystemUI/res/values-it/strings.xml deleted file mode 100644 index f4f7ab719661..000000000000 --- a/packages/CarSystemUI/res/values-it/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Riconoscimento vocale gestito da dispos. Bluetooth connesso"</string> - <string name="car_guest" msgid="318393171202663722">"Ospite"</string> - <string name="start_guest_session" msgid="497784785761754874">"Ospite"</string> - <string name="car_add_user" msgid="4067337059622483269">"Aggiungi utente"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nuovo utente"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Il nuovo utente, una volta aggiunto, dovrà configurare il suo spazio."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualsiasi utente può aggiornare le app per tutti gli altri."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Caricamento"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Caricamento dell\'utente (da <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-iw/strings.xml b/packages/CarSystemUI/res/values-iw/strings.xml deleted file mode 100644 index a044b23709e1..000000000000 --- a/packages/CarSystemUI/res/values-iw/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"מינ\'"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"מקס\'"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"הזיהוי הקולי מתבצע עכשיו במכשיר Bluetooth מחובר"</string> - <string name="car_guest" msgid="318393171202663722">"אורח"</string> - <string name="start_guest_session" msgid="497784785761754874">"אורח"</string> - <string name="car_add_user" msgid="4067337059622483269">"הוספת משתמש"</string> - <string name="car_new_user" msgid="6637442369728092473">"משתמש חדש"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"בעת הוספת משתמש חדש, על משתמש זה להגדיר את המרחב שלו."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"כל משתמש יכול לעדכן אפליקציות לכל שאר המשתמשים."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"בטעינה"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"המשתמש בטעינה (מהמשתמש <xliff:g id="FROM_USER">%1$d</xliff:g> אל <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ja/strings.xml b/packages/CarSystemUI/res/values-ja/strings.xml deleted file mode 100644 index aae7dbff155e..000000000000 --- a/packages/CarSystemUI/res/values-ja/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Bluetooth 接続デバイスで音声認識が処理されるようになりました"</string> - <string name="car_guest" msgid="318393171202663722">"ゲスト"</string> - <string name="start_guest_session" msgid="497784785761754874">"ゲスト"</string> - <string name="car_add_user" msgid="4067337059622483269">"ユーザーを追加"</string> - <string name="car_new_user" msgid="6637442369728092473">"新しいユーザー"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"どのユーザーも他のすべてのユーザーに代わってアプリを更新できます。"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"読み込んでいます"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ユーザーを読み込んでいます(<xliff:g id="FROM_USER">%1$d</xliff:g>~<xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ka/strings.xml b/packages/CarSystemUI/res/values-ka/strings.xml deleted file mode 100644 index 19894d164189..000000000000 --- a/packages/CarSystemUI/res/values-ka/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"მინ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"მაქს"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ხმის ამოცნობა დამუშავდება დაკავშირებული Bluetooth-მოწყობილობით"</string> - <string name="car_guest" msgid="318393171202663722">"სტუმარი"</string> - <string name="start_guest_session" msgid="497784785761754874">"სტუმარი"</string> - <string name="car_add_user" msgid="4067337059622483269">"მომხმარებლის დამატება"</string> - <string name="car_new_user" msgid="6637442369728092473">"ახალი მომხმარებელი"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის გამართვა მოუწევს."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"იტვირთება"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"იტვირთება მომხმარებელი (<xliff:g id="FROM_USER">%1$d</xliff:g>-დან <xliff:g id="TO_USER">%2$d</xliff:g>-მდე)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-kk/strings.xml b/packages/CarSystemUI/res/values-kk/strings.xml deleted file mode 100644 index 5220aa5bf1bd..000000000000 --- a/packages/CarSystemUI/res/values-kk/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Дауысты тану үшін Bluetooth құрылғысы пайдаланылады."</string> - <string name="car_guest" msgid="318393171202663722">"Қонақ"</string> - <string name="start_guest_session" msgid="497784785761754874">"Қонақ"</string> - <string name="car_add_user" msgid="4067337059622483269">"Пайдаланушыны енгізу"</string> - <string name="car_new_user" msgid="6637442369728092473">"Жаңа пайдаланушы"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Қосылған жаңа пайдаланушы өз профилін реттеуі керек."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Кез келген пайдаланушы қолданбаларды басқа пайдаланушылар үшін жаңарта алады."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Жүктелуде"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Пайдаланушы профилі жүктелуде (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-km/strings.xml b/packages/CarSystemUI/res/values-km/strings.xml deleted file mode 100644 index fbcab8431476..000000000000 --- a/packages/CarSystemUI/res/values-km/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"អប្បបរមា"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"អតិបរិមា"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ឥឡូវនេះ ការសម្គាល់សំឡេងត្រូវបានចាត់ចែងដោយឧបករណ៍ដែលបានភ្ជាប់ប៊្លូធូស"</string> - <string name="car_guest" msgid="318393171202663722">"ភ្ញៀវ"</string> - <string name="start_guest_session" msgid="497784785761754874">"ភ្ញៀវ"</string> - <string name="car_add_user" msgid="4067337059622483269">"បញ្ចូលអ្នកប្រើប្រាស់"</string> - <string name="car_new_user" msgid="6637442369728092473">"អ្នកប្រើប្រាស់ថ្មី"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"នៅពេលដែលអ្នកបញ្ចូលអ្នកប្រើប្រាស់ថ្មី បុគ្គលនោះត្រូវតែរៀបចំទំហំផ្ទុករបស់គេ។"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"អ្នកប្រើប្រាស់ណាក៏អាចដំឡើងកំណែកម្មវិធីសម្រាប់អ្នកប្រើប្រាស់ទាំងអស់ផ្សេងទៀតបានដែរ។"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"កំពុងផ្ទុក"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"កំពុងផ្ទុកអ្នកប្រើប្រាស់ (ពី <xliff:g id="FROM_USER">%1$d</xliff:g> ដល់ <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-kn/strings.xml b/packages/CarSystemUI/res/values-kn/strings.xml deleted file mode 100644 index 21c4cc02e207..000000000000 --- a/packages/CarSystemUI/res/values-kn/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ಕನಿಷ್ಠ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ಗರಿಷ್ಠ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ಇದೀಗ ಕನೆಕ್ಟ್ ಆದ ಬ್ಲೂಟೂತ್ ಸಾಧನ ಧ್ವನಿ ಗುರುತಿಸುವಿಕೆ ನಿರ್ವಹಿಸಿದೆ"</string> - <string name="car_guest" msgid="318393171202663722">"ಅತಿಥಿ"</string> - <string name="start_guest_session" msgid="497784785761754874">"ಅತಿಥಿ"</string> - <string name="car_add_user" msgid="4067337059622483269">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string> - <string name="car_new_user" msgid="6637442369728092473">"ಹೊಸ ಬಳಕೆದಾರ"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ನೀವು ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಆ್ಯಪ್ಗಳನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬಹುದು."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ಬಳಕೆದಾರರನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ (<xliff:g id="FROM_USER">%1$d</xliff:g> ನಿಂದ <xliff:g id="TO_USER">%2$d</xliff:g> ವರೆಗೆ)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ko/strings.xml b/packages/CarSystemUI/res/values-ko/strings.xml deleted file mode 100644 index 6b670b018814..000000000000 --- a/packages/CarSystemUI/res/values-ko/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"최소"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"최대"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"이제 연결된 블루투스 기기에서 음성 인식이 처리됩니다."</string> - <string name="car_guest" msgid="318393171202663722">"게스트"</string> - <string name="start_guest_session" msgid="497784785761754874">"게스트"</string> - <string name="car_add_user" msgid="4067337059622483269">"사용자 추가"</string> - <string name="car_new_user" msgid="6637442369728092473">"신규 사용자"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"추가된 신규 사용자는 자신만의 공간을 설정해야 합니다."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"누구나 다른 모든 사용자를 위해 앱을 업데이트할 수 있습니다."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"로드 중"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"사용자 로드 중(<xliff:g id="FROM_USER">%1$d</xliff:g>님에서 <xliff:g id="TO_USER">%2$d</xliff:g>님으로)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ky/strings.xml b/packages/CarSystemUI/res/values-ky/strings.xml deleted file mode 100644 index b3b355a42aa8..000000000000 --- a/packages/CarSystemUI/res/values-ky/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Үндү эми туташкан Bluetooth түзмөгү менен тааныса болот"</string> - <string name="car_guest" msgid="318393171202663722">"Конок"</string> - <string name="start_guest_session" msgid="497784785761754874">"Конок"</string> - <string name="car_add_user" msgid="4067337059622483269">"Колдонуучу кошуу"</string> - <string name="car_new_user" msgid="6637442369728092473">"Жаңы колдонуучу"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Жаңы колдонуучу кошулганда, ал өзүнүн профилин жөндөп алышы керек."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Колдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Жүктөлүүдө"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Колдонуучу тууралуу маалымат жүктөлүүдө (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-lo/strings.xml b/packages/CarSystemUI/res/values-lo/strings.xml deleted file mode 100644 index d2199e2a0cef..000000000000 --- a/packages/CarSystemUI/res/values-lo/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ນທ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ສູງສຸດ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ການຈຳແນກສຽງເວົ້າດຽວນີ້ຈັດການໂດຍອຸປະກອນ Bluetooth ທີ່ເຊື່ອມຕໍ່"</string> - <string name="car_guest" msgid="318393171202663722">"ແຂກ"</string> - <string name="start_guest_session" msgid="497784785761754874">"ແຂກ"</string> - <string name="car_add_user" msgid="4067337059622483269">"ເພີ່ມຜູ້ໃຊ້"</string> - <string name="car_new_user" msgid="6637442369728092473">"ຜູ້ໃຊ້ໃໝ່"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ເມື່ອທ່ານເພີ່ມຜູ້ໃຊ້ໃໝ່, ບຸກຄົນນັ້ນຈຳເປັນຕ້ອງຕັ້ງຄ່າພື້ນທີ່ຂອງເຂົາເຈົ້າ."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ຜູ້ໃຊ້ຕ່າງໆສາມາດອັບເດດແອັບສຳລັບຜູ້ໃຊ້ອື່ນທັງໝົດໄດ້."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ກຳລັງໂຫຼດ"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ກຳລັງໂຫຼດຜູ້ໃຊ້ (ຈາກ <xliff:g id="FROM_USER">%1$d</xliff:g> ໄປຍັງ <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-lt/strings.xml b/packages/CarSystemUI/res/values-lt/strings.xml deleted file mode 100644 index 26690002416e..000000000000 --- a/packages/CarSystemUI/res/values-lt/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Didž."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Balso atpažinimą dabar tvarko susietas „Bluetooth“ įrenginys"</string> - <string name="car_guest" msgid="318393171202663722">"Svečias"</string> - <string name="start_guest_session" msgid="497784785761754874">"Svečias"</string> - <string name="car_add_user" msgid="4067337059622483269">"Pridėti naudotoją"</string> - <string name="car_new_user" msgid="6637442369728092473">"Naujas naudotojas"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo vietą."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Bet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Įkeliama"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Įkeliamas naudotojo profilis (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-lv/strings.xml b/packages/CarSystemUI/res/values-lv/strings.xml deleted file mode 100644 index 87b4ede4383a..000000000000 --- a/packages/CarSystemUI/res/values-lv/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Balss atpazīšanu tagad nodrošina pievienotā Bluetooth ierīce"</string> - <string name="car_guest" msgid="318393171202663722">"Viesis"</string> - <string name="start_guest_session" msgid="497784785761754874">"Viesis"</string> - <string name="car_add_user" msgid="4067337059622483269">"Pievienot lietotāju"</string> - <string name="car_new_user" msgid="6637442369728092473">"Jauns lietotājs"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kad pievienojat jaunu lietotāju, viņam ir jāizveido savs profils."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Ikviens lietotājs var atjaunināt lietotnes visu lietotāju vārdā."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Notiek ielāde…"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Notiek lietotāja profila ielāde (<xliff:g id="FROM_USER">%1$d</xliff:g>–<xliff:g id="TO_USER">%2$d</xliff:g>)…"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-mk/strings.xml b/packages/CarSystemUI/res/values-mk/strings.xml deleted file mode 100644 index f8fd02cb071d..000000000000 --- a/packages/CarSystemUI/res/values-mk/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Поврзаниот уред со Bluetooth управува со препознавањето глас"</string> - <string name="car_guest" msgid="318393171202663722">"Гостин"</string> - <string name="start_guest_session" msgid="497784785761754874">"Гостин"</string> - <string name="car_add_user" msgid="4067337059622483269">"Додај корисник"</string> - <string name="car_new_user" msgid="6637442369728092473">"Нов корисник"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Кога додавате нов корисник, тоа лице треба да го постави својот простор."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Секој корисник може да ажурира апликации за сите други корисници."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Се вчитува"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Се вчитува корисникот (од <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ml/strings.xml b/packages/CarSystemUI/res/values-ml/strings.xml deleted file mode 100644 index 343157160105..000000000000 --- a/packages/CarSystemUI/res/values-ml/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"മിനിമം"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"മാക്സിമം"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"കണക്റ്റ് ചെയ്ത Bluetooth ഉപകരണം വഴി ഇപ്പോൾ വോയ്സ് തിരിച്ചറിയൽ കെെകാര്യം ചെയ്യുന്നു"</string> - <string name="car_guest" msgid="318393171202663722">"അതിഥി"</string> - <string name="start_guest_session" msgid="497784785761754874">"അതിഥി"</string> - <string name="car_add_user" msgid="4067337059622483269">"ഉപയോക്താവിനെ ചേർക്കുക"</string> - <string name="car_new_user" msgid="6637442369728092473">"പുതിയ ഉപയോക്താവ്"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"നിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തി സ്വന്തം ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ഏതൊരു ഉപയോക്താവിനും മറ്റെല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാനാവും."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ലോഡ് ചെയ്യുന്നു"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ഉപയോക്തൃ പ്രൊഫൈൽ ലോഡ് ചെയ്യുന്നു (<xliff:g id="FROM_USER">%1$d</xliff:g> എന്നതിൽ നിന്ന് <xliff:g id="TO_USER">%2$d</xliff:g> എന്നതിലേക്ക്)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-mn/strings.xml b/packages/CarSystemUI/res/values-mn/strings.xml deleted file mode 100644 index 5bd76dc7e067..000000000000 --- a/packages/CarSystemUI/res/values-mn/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Бага"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Их"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Одоо дуугаар танихыг холбогдсон Bluetooth төхөөрөмж удирдана"</string> - <string name="car_guest" msgid="318393171202663722">"Зочин"</string> - <string name="start_guest_session" msgid="497784785761754874">"Зочин"</string> - <string name="car_add_user" msgid="4067337059622483269">"Хэрэглэгч нэмэх"</string> - <string name="car_new_user" msgid="6637442369728092473">"Шинэ хэрэглэгч"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Та шинэ хэрэглэгч нэмэх үед тухайн хэрэглэгч хувийн орон зайгаа тохируулах шаардлагатай."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Бусад бүх хэрэглэгчийн аппыг дурын хэрэглэгч шинэчлэх боломжтой."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Ачаалж байна"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Хэрэглэгчийг ачаалж байна (<xliff:g id="FROM_USER">%1$d</xliff:g>-с <xliff:g id="TO_USER">%2$d</xliff:g> хүртэл)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-mr/strings.xml b/packages/CarSystemUI/res/values-mr/strings.xml deleted file mode 100644 index 2366465e1a9f..000000000000 --- a/packages/CarSystemUI/res/values-mr/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"मि"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"कमाल"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"आता कनेक्ट केलेले ब्लूटूथ डिव्हाइस व्हॉइस रेकग्निशन हाताळते"</string> - <string name="car_guest" msgid="318393171202663722">"अतिथी"</string> - <string name="start_guest_session" msgid="497784785761754874">"अतिथी"</string> - <string name="car_add_user" msgid="4067337059622483269">"वापरकर्ता जोडा"</string> - <string name="car_new_user" msgid="6637442369728092473">"नवीन वापरकर्ता"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"तुम्ही नवीन वापरकर्ता जोडता तेव्हा त्या व्यक्तीने त्यांची जागा सेट करणे आवश्यक असते."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"कोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अॅप्स अपडेट करू शकतो."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"लोड करत आहे"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"वापरकर्ता लोड करत आहे (<xliff:g id="FROM_USER">%1$d</xliff:g> पासून <xliff:g id="TO_USER">%2$d</xliff:g> पर्यंत)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ms/strings.xml b/packages/CarSystemUI/res/values-ms/strings.xml deleted file mode 100644 index 29ac83afc12c..000000000000 --- a/packages/CarSystemUI/res/values-ms/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Pengecaman suara kini dikendalikan peranti Bluetooth tersmbg"</string> - <string name="car_guest" msgid="318393171202663722">"Tetamu"</string> - <string name="start_guest_session" msgid="497784785761754874">"Tetamu"</string> - <string name="car_add_user" msgid="4067337059622483269">"Tambah Pengguna"</string> - <string name="car_new_user" msgid="6637442369728092473">"Pengguna Baharu"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Apabila anda menambahkan pengguna baharu, orang itu perlu menyediakan ruang mereka."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Mana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Memuatkan"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Memuatkan pengguna (daripada <xliff:g id="FROM_USER">%1$d</xliff:g> hingga <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-my/strings.xml b/packages/CarSystemUI/res/values-my/strings.xml deleted file mode 100644 index 7f240b430471..000000000000 --- a/packages/CarSystemUI/res/values-my/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"နိမ့်"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"မြင့်"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ချိတ်ထားသော ဘလူးတုသ်စက်ဖြင့် အသံမှတ်သားမှုကို ထိန်းချုပ်သည်"</string> - <string name="car_guest" msgid="318393171202663722">"ဧည့်သည်"</string> - <string name="start_guest_session" msgid="497784785761754874">"ဧည့်သည်"</string> - <string name="car_add_user" msgid="4067337059622483269">"အသုံးပြုသူ ထည့်ရန်"</string> - <string name="car_new_user" msgid="6637442369728092473">"အသုံးပြုသူ အသစ်"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"အသုံးပြုသူအသစ် ထည့်သည့်အခါ ထိုသူသည် မိမိ၏ နေရာကို စနစ်ထည့်သွင်းရပါမည်။"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"မည်သူမဆို အသုံးပြုသူအားလုံးအတွက် အက်ပ်များကို အပ်ဒိတ်လုပ်နိုင်သည်။"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ဖွင့်နေသည်"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"အသုံးပြုသူကို ဖွင့်နေသည် (<xliff:g id="FROM_USER">%1$d</xliff:g> မှ <xliff:g id="TO_USER">%2$d</xliff:g> သို့)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-nb/strings.xml b/packages/CarSystemUI/res/values-nb/strings.xml deleted file mode 100644 index c1cfcf727859..000000000000 --- a/packages/CarSystemUI/res/values-nb/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Talegjenkjenning håndteres nå av tilkoblet Bluetooth-enhet"</string> - <string name="car_guest" msgid="318393171202663722">"Gjest"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gjest"</string> - <string name="car_add_user" msgid="4067337059622483269">"Legg til bruker"</string> - <string name="car_new_user" msgid="6637442369728092473">"Ny bruker"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Alle brukere kan oppdatere apper for alle andre brukere."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Laster inn"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Laster inn brukeren (fra <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ne/strings.xml b/packages/CarSystemUI/res/values-ne/strings.xml deleted file mode 100644 index 40639dedc4b5..000000000000 --- a/packages/CarSystemUI/res/values-ne/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"न्यूनतम"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"अधिकतम"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"अब ब्लुटुथ मार्फत जोडिएको यन्त्रले आवाज पहिचान गर्ने कार्य सम्हाल्छ"</string> - <string name="car_guest" msgid="318393171202663722">"अतिथि"</string> - <string name="start_guest_session" msgid="497784785761754874">"अतिथि"</string> - <string name="car_add_user" msgid="4067337059622483269">"प्रयोगकर्ता थप्नुहोस्"</string> - <string name="car_new_user" msgid="6637442369728092473">"नयाँ प्रयोगकर्ता"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"तपाईंले नयाँ प्रयोगकर्ता थप्दा ती व्यक्तिले आफ्नो स्थान सेटअप गर्नु पर्छ।"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"सबै प्रयोगकर्ताले अन्य प्रयोगकर्ताका एपहरू अद्यावधिक गर्न सक्छन्।"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"लोड गरिँदै"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"प्रयोगकर्तासम्बन्धी जानकारी लोड गरिँदै (<xliff:g id="FROM_USER">%1$d</xliff:g> बाट <xliff:g id="TO_USER">%2$d</xliff:g> मा)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-nl/strings.xml b/packages/CarSystemUI/res/values-nl/strings.xml deleted file mode 100644 index 95a76467b078..000000000000 --- a/packages/CarSystemUI/res/values-nl/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Spraakherkenning actief via een verbonden bluetooth-apparaat"</string> - <string name="car_guest" msgid="318393171202663722">"Gast"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gast"</string> - <string name="car_add_user" msgid="4067337059622483269">"Gebruiker toevoegen"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nieuwe gebruiker"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Als je een nieuwe gebruiker toevoegt, moet die persoon een eigen profiel instellen."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Elke gebruiker kan apps updaten voor alle andere gebruikers"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Laden"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Gebruiker laden (van <xliff:g id="FROM_USER">%1$d</xliff:g> naar <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-or/strings.xml b/packages/CarSystemUI/res/values-or/strings.xml deleted file mode 100644 index b0b59b348594..000000000000 --- a/packages/CarSystemUI/res/values-or/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ସର୍ବନିମ୍ନ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ସର୍ବାଧିକ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ଭଏସ ଚିହ୍ନଟକରଣ ଏବେ ସଂଯୁକ୍ତ ଥିବା ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଦ୍ୱାରା ପରିଚାଳିତ"</string> - <string name="car_guest" msgid="318393171202663722">"ଅତିଥି"</string> - <string name="start_guest_session" msgid="497784785761754874">"ଅତିଥି"</string> - <string name="car_add_user" msgid="4067337059622483269">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string> - <string name="car_new_user" msgid="6637442369728092473">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରିବା ବେଳେ ସେହି ବ୍ୟକ୍ତିଙ୍କୁ ତାଙ୍କ ସ୍ଥାନ ସେଟ୍ ଅପ୍ କରିବାର ଆବଶ୍ୟକତା ଅଛି।"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ଯେ କୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଆପଗୁଡ଼ିକୁ ଅପଡେଟ୍ କରିପାରିବେ।"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ଲୋଡ୍ କରାଯାଉଛି"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଲୋଡ୍ କରାଯାଉଛି (<xliff:g id="FROM_USER">%1$d</xliff:g>ଙ୍କ ଠାରୁ <xliff:g id="TO_USER">%2$d</xliff:g> ପର୍ଯ୍ୟନ୍ତ)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-pa/strings.xml b/packages/CarSystemUI/res/values-pa/strings.xml deleted file mode 100644 index e7efca1894b7..000000000000 --- a/packages/CarSystemUI/res/values-pa/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"ਨਿਊਨਤਮ"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"ਅਧਿਕਤਮ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ਅਵਾਜ਼ ਦੀ ਪਛਾਣ ਨੂੰ ਹੁਣ ਕਨੈਕਟ ਕੀਤਾ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸ ਸੰਭਾਲਦਾ ਹੈ"</string> - <string name="car_guest" msgid="318393171202663722">"ਮਹਿਮਾਨ"</string> - <string name="start_guest_session" msgid="497784785761754874">"ਮਹਿਮਾਨ"</string> - <string name="car_add_user" msgid="4067337059622483269">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string> - <string name="car_new_user" msgid="6637442369728092473">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ਜਦੋਂ ਤੁਸੀਂ ਕੋਈ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ਵਰਤੋਂਕਾਰ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ (<xliff:g id="FROM_USER">%1$d</xliff:g> ਤੋਂ <xliff:g id="TO_USER">%2$d</xliff:g> ਤੱਕ)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-pl/strings.xml b/packages/CarSystemUI/res/values-pl/strings.xml deleted file mode 100644 index 37d0ef171599..000000000000 --- a/packages/CarSystemUI/res/values-pl/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznawanie mowy przez połączone urządzenie Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Gość"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gość"</string> - <string name="car_add_user" msgid="4067337059622483269">"Dodaj użytkownika"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nowy użytkownik"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Każdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Ładuję"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ładuję użytkownika (od <xliff:g id="FROM_USER">%1$d</xliff:g> do <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-pt-rPT/strings.xml b/packages/CarSystemUI/res/values-pt-rPT/strings.xml deleted file mode 100644 index 182f5b58d1b1..000000000000 --- a/packages/CarSystemUI/res/values-pt-rPT/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconhecimento de voz agora através do disp. Bluetooth lig."</string> - <string name="car_guest" msgid="318393171202663722">"Convidado"</string> - <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string> - <string name="car_add_user" msgid="4067337059622483269">"Adicionar utilizador"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novo utilizador"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualquer utilizador pode atualizar apps para todos os outros utilizadores."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"A carregar…"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"A carregar o utilizador (de <xliff:g id="FROM_USER">%1$d</xliff:g> para <xliff:g id="TO_USER">%2$d</xliff:g>)…"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-pt/strings.xml b/packages/CarSystemUI/res/values-pt/strings.xml deleted file mode 100644 index 5c8394a51599..000000000000 --- a/packages/CarSystemUI/res/values-pt/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Mín"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Máx"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconhecimento de voz com dispositivo Bluetooth conectado"</string> - <string name="car_guest" msgid="318393171202663722">"Convidado"</string> - <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string> - <string name="car_add_user" msgid="4067337059622483269">"Adicionar usuário"</string> - <string name="car_new_user" msgid="6637442369728092473">"Novo usuário"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Quando você adiciona um usuário novo, essa pessoa precisa configurar o espaço dela."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualquer usuário pode atualizar apps para os demais usuários."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Carregando"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Carregando usuário (de <xliff:g id="FROM_USER">%1$d</xliff:g> para <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ro/strings.xml b/packages/CarSystemUI/res/values-ro/strings.xml deleted file mode 100644 index 25ecbb6453b0..000000000000 --- a/packages/CarSystemUI/res/values-ro/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Recunoașterea vocală acum gestionată de dispozitivul Bluetooth conectat"</string> - <string name="car_guest" msgid="318393171202663722">"Invitat"</string> - <string name="start_guest_session" msgid="497784785761754874">"Invitat"</string> - <string name="car_add_user" msgid="4067337059622483269">"Adăugați un utilizator"</string> - <string name="car_new_user" msgid="6637442369728092473">"Utilizator nou"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Orice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Se încarcă"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Se încarcă utilizatorul (de la <xliff:g id="FROM_USER">%1$d</xliff:g> la <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ru/strings.xml b/packages/CarSystemUI/res/values-ru/strings.xml deleted file mode 100644 index e93d25d1acdc..000000000000 --- a/packages/CarSystemUI/res/values-ru/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Для распознавания речи используется Bluetooth-устройство."</string> - <string name="car_guest" msgid="318393171202663722">"Гость"</string> - <string name="start_guest_session" msgid="497784785761754874">"Гость"</string> - <string name="car_add_user" msgid="4067337059622483269">"Добавить пользователя"</string> - <string name="car_new_user" msgid="6637442369728092473">"Новый пользователь"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Когда вы добавите пользователя, ему потребуется настроить профиль."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Любой пользователь устройства может обновлять приложения для всех аккаунтов."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Загрузка…"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Загрузка профиля пользователя (с <xliff:g id="FROM_USER">%1$d</xliff:g> по <xliff:g id="TO_USER">%2$d</xliff:g>)…"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-si/strings.xml b/packages/CarSystemUI/res/values-si/strings.xml deleted file mode 100644 index 947cb0a53206..000000000000 --- a/packages/CarSystemUI/res/values-si/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"අවම"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"උපරිම"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"හඬ හැඳුනුම දැන් සම්බන්ධ බ්ලූටූත් උපාංගය මගින් හසුරුවනු ලැබේ"</string> - <string name="car_guest" msgid="318393171202663722">"අමුත්තා"</string> - <string name="start_guest_session" msgid="497784785761754874">"අමුත්තා"</string> - <string name="car_add_user" msgid="4067337059622483269">"පරිශීලක එක් කරන්න"</string> - <string name="car_new_user" msgid="6637442369728092473">"නව පරිශීලක"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"ඔබ අලුත් පරිශීලකයෙකු එක් කරන විට, එම පුද්ගලයා තමන්ගේ ඉඩ සකසා ගැනීමට අවශ්ය වේ."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"සියලුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යෙදුම් යාවත්කාලීන කළ හැක."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"පූරණය වෙමින්"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"පරිශීලකයා පූරණය වෙමින් (<xliff:g id="FROM_USER">%1$d</xliff:g> සිට <xliff:g id="TO_USER">%2$d</xliff:g> වෙත)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sk/strings.xml b/packages/CarSystemUI/res/values-sk/strings.xml deleted file mode 100644 index 2016b7b18adf..000000000000 --- a/packages/CarSystemUI/res/values-sk/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"max."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznávanie hlasu teraz prebieha v pripoj. zar. Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Hosť"</string> - <string name="start_guest_session" msgid="497784785761754874">"Hosť"</string> - <string name="car_add_user" msgid="4067337059622483269">"Pridať používateľa"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nový používateľ"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Každý používateľ môže aktualizovať aplikácie pre všetkých ostatných používateľov."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Načítava sa"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Načítava sa používateľ (predchádzajúci: <xliff:g id="FROM_USER">%1$d</xliff:g>, nasledujúci: <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sl/strings.xml b/packages/CarSystemUI/res/values-sl/strings.xml deleted file mode 100644 index 32fd50e9cb8b..000000000000 --- a/packages/CarSystemUI/res/values-sl/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Najn."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Najv."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanje glasu zdaj izvaja povezana naprava Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Gost"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gost"</string> - <string name="car_add_user" msgid="4067337059622483269">"Dodaj uporabnika"</string> - <string name="car_new_user" msgid="6637442369728092473">"Nov uporabnik"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Vsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Nalaganje"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nalaganje uporabnika (od uporabnika <xliff:g id="FROM_USER">%1$d</xliff:g> do uporabnika <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sq/strings.xml b/packages/CarSystemUI/res/values-sq/strings.xml deleted file mode 100644 index 6fdd06c7d4d6..000000000000 --- a/packages/CarSystemUI/res/values-sq/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Njohja zanore trajtohet nga pajisja me Bluetooth-in e lidhur"</string> - <string name="car_guest" msgid="318393171202663722">"I ftuar"</string> - <string name="start_guest_session" msgid="497784785761754874">"I ftuar"</string> - <string name="car_add_user" msgid="4067337059622483269">"Shto përdorues"</string> - <string name="car_new_user" msgid="6637442369728092473">"Përdorues i ri"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Çdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Po ngarkohet"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Përdoruesi po ngarkohet (nga <xliff:g id="FROM_USER">%1$d</xliff:g> te <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sr/strings.xml b/packages/CarSystemUI/res/values-sr/strings.xml deleted file mode 100644 index 494aeaa0f1f9..000000000000 --- a/packages/CarSystemUI/res/values-sr/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maкс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Препознавањем гласа сада управља повезани Bluetooth уређај"</string> - <string name="car_guest" msgid="318393171202663722">"Гост"</string> - <string name="start_guest_session" msgid="497784785761754874">"Гост"</string> - <string name="car_add_user" msgid="4067337059622483269">"Додај корисника"</string> - <string name="car_new_user" msgid="6637442369728092473">"Нови корисник"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Када додате новог корисника, та особа треба да подеси свој простор."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Сваки корисник може да ажурира апликације за све остале кориснике."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Учитава се"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Профил корисника се учитава (из<xliff:g id="FROM_USER">%1$d</xliff:g> у <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sv/strings.xml b/packages/CarSystemUI/res/values-sv/strings.xml deleted file mode 100644 index 65481cdf2533..000000000000 --- a/packages/CarSystemUI/res/values-sv/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Nu hanteras röstigenkänning via en anstluten Bluetooth-enhet"</string> - <string name="car_guest" msgid="318393171202663722">"Gäst"</string> - <string name="start_guest_session" msgid="497784785761754874">"Gäst"</string> - <string name="car_add_user" msgid="4067337059622483269">"Lägg till användare"</string> - <string name="car_new_user" msgid="6637442369728092473">"Ny användare"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Alla användare kan uppdatera appar för andra användare."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Läser in"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Läser in användare (från <xliff:g id="FROM_USER">%1$d</xliff:g> till <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-sw/strings.xml b/packages/CarSystemUI/res/values-sw/strings.xml deleted file mode 100644 index a79d628e6786..000000000000 --- a/packages/CarSystemUI/res/values-sw/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Chini"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Juu"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Utambuzi wa sauti sasa unashughulikiwa na kifaa kilichounganishwa cha Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Mgeni"</string> - <string name="start_guest_session" msgid="497784785761754874">"Mgeni"</string> - <string name="car_add_user" msgid="4067337059622483269">"Ongeza Mtumiaji"</string> - <string name="car_new_user" msgid="6637442369728092473">"Mtumiaji Mpya"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ukiongeza mtumiaji mpya, ni lazima aweke kikundi chake."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Mtumiaji yeyote anaweza kusasisha programu za watumiaji wengine."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Inapakia"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Inapakia wasifu wa mtumiaji (kutoka <xliff:g id="FROM_USER">%1$d</xliff:g> kuwa <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ta/strings.xml b/packages/CarSystemUI/res/values-ta/strings.xml deleted file mode 100644 index 849b40d36ccd..000000000000 --- a/packages/CarSystemUI/res/values-ta/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"குறைந்தபட்சம்"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"அதிகபட்சம்"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"இணைக்கப்பட்ட புளூடூத் சாதனத்தால் \'குரல் அறிதல்\' கையாளப்படுகிறது"</string> - <string name="car_guest" msgid="318393171202663722">"கெஸ்ட்"</string> - <string name="start_guest_session" msgid="497784785761754874">"கெஸ்ட்"</string> - <string name="car_add_user" msgid="4067337059622483269">"பயனரைச் சேருங்கள்"</string> - <string name="car_new_user" msgid="6637442369728092473">"புதிய பயனர்"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"புதிய பயனரைச் சேர்க்கும்போது அவர் தனக்கான சேமிப்பிடத்தை அமைக்க வேண்டும்."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"எந்தப் பயனரும் பிற பயனர்கள் சார்பாக ஆப்ஸைப் புதுப்பிக்க முடியும்."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"ஏற்றுகிறது"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"பயனர் தகவலை ஏற்றுகிறது (<xliff:g id="FROM_USER">%1$d</xliff:g>லிருந்து <xliff:g id="TO_USER">%2$d</xliff:g> வரை)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-te/strings.xml b/packages/CarSystemUI/res/values-te/strings.xml deleted file mode 100644 index 83bb24a64a46..000000000000 --- a/packages/CarSystemUI/res/values-te/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"కని."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"గరి."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"నేడు వాయిస్ గుర్తింపును కనెక్ట్ అయిన బ్లూటూత్ నిర్వహిస్తోంది"</string> - <string name="car_guest" msgid="318393171202663722">"గెస్ట్"</string> - <string name="start_guest_session" msgid="497784785761754874">"గెస్ట్"</string> - <string name="car_add_user" msgid="4067337059622483269">"యూజర్ను జోడించండి"</string> - <string name="car_new_user" msgid="6637442369728092473">"కొత్త యూజర్"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"మీరు కొత్త యూజర్ను జోడించినప్పుడు, ఆ వ్యక్తి తన స్పేస్ను సెటప్ చేసుకోవాలి."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ఏ యూజర్ అయినా మిగతా యూజర్ల కోసం యాప్లను అప్డేట్ చేయవచ్చు."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"లోడ్ అవుతోంది"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"యూజర్ను లోడ్ చేస్తోంది (<xliff:g id="FROM_USER">%1$d</xliff:g> నుండి <xliff:g id="TO_USER">%2$d</xliff:g> వరకు)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-th/strings.xml b/packages/CarSystemUI/res/values-th/strings.xml deleted file mode 100644 index fa99ac1928c1..000000000000 --- a/packages/CarSystemUI/res/values-th/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"ตอนนี้อุปกรณ์บลูทูธที่เชื่อมต่อจะจัดการการจดจำเสียง"</string> - <string name="car_guest" msgid="318393171202663722">"ผู้ใช้ชั่วคราว"</string> - <string name="start_guest_session" msgid="497784785761754874">"ผู้ใช้ชั่วคราว"</string> - <string name="car_add_user" msgid="4067337059622483269">"เพิ่มผู้ใช้"</string> - <string name="car_new_user" msgid="6637442369728092473">"ผู้ใช้ใหม่"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"ผู้ใช้ทุกคนจะอัปเดตแอปให้แก่ผู้ใช้คนอื่นๆ ได้"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"กำลังโหลด"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"กำลังโหลดผู้ใช้ (จาก <xliff:g id="FROM_USER">%1$d</xliff:g> ถึง <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-tl/strings.xml b/packages/CarSystemUI/res/values-tl/strings.xml deleted file mode 100644 index c6f5f59acf0d..000000000000 --- a/packages/CarSystemUI/res/values-tl/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Minuto"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Hawak na ngayon ng Bluetooth device ang Pagkilala ng boses"</string> - <string name="car_guest" msgid="318393171202663722">"Bisita"</string> - <string name="start_guest_session" msgid="497784785761754874">"Bisita"</string> - <string name="car_add_user" msgid="4067337059622483269">"Magdagdag ng User"</string> - <string name="car_new_user" msgid="6637442369728092473">"Bagong User"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Puwedeng i-update ng sinumang user ang mga app para sa lahat ng iba pang user."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Naglo-load"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nilo-load ang user (mula kay <xliff:g id="FROM_USER">%1$d</xliff:g> papunta kay <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-tr/strings.xml b/packages/CarSystemUI/res/values-tr/strings.xml deleted file mode 100644 index a76812769dae..000000000000 --- a/packages/CarSystemUI/res/values-tr/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Artık ses tanıma, bağlı Bluetooth cihazı tarafından işleniyor"</string> - <string name="car_guest" msgid="318393171202663722">"Misafir"</string> - <string name="start_guest_session" msgid="497784785761754874">"Misafir"</string> - <string name="car_add_user" msgid="4067337059622483269">"Kullanıcı Ekle"</string> - <string name="car_new_user" msgid="6637442369728092473">"Yeni Kullanıcı"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yeni kullanıcı eklediğinizde, bu kişinin alanını ayarlaması gerekir."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Herhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Yükleniyor"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Kullanıcı yükleniyor (<xliff:g id="FROM_USER">%1$d</xliff:g> kullanıcısından <xliff:g id="TO_USER">%2$d</xliff:g> kullanıcısına)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-uk/strings.xml b/packages/CarSystemUI/res/values-uk/strings.xml deleted file mode 100644 index c424d87ace6e..000000000000 --- a/packages/CarSystemUI/res/values-uk/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Мін."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Голос розпізнається через підключений пристрій Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Гість"</string> - <string name="start_guest_session" msgid="497784785761754874">"Гість"</string> - <string name="car_add_user" msgid="4067337059622483269">"Додати користувача"</string> - <string name="car_new_user" msgid="6637442369728092473">"Новий користувач"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Коли ви додаєте нового користувача, він має налаштувати свій профіль."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Усі користувачі можуть оновлювати додатки для решти людей."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Завантаження"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Завантаження профілю користувача (від <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-ur/strings.xml b/packages/CarSystemUI/res/values-ur/strings.xml deleted file mode 100644 index 063dcbc4ecd1..000000000000 --- a/packages/CarSystemUI/res/values-ur/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"کم از کم"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"زیادہ سے زیادہ"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"آواز کی شناخت اب منسلک کردہ بلوٹوتھ آلے سے ہوتی ہے"</string> - <string name="car_guest" msgid="318393171202663722">"مہمان"</string> - <string name="start_guest_session" msgid="497784785761754874">"مہمان"</string> - <string name="car_add_user" msgid="4067337059622483269">"صارف شامل کریں"</string> - <string name="car_new_user" msgid="6637442369728092473">"نیا صارف"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ سیٹ کرنی ہوتی ہے۔"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"کوئی بھی صارف دیگر سبھی صارفین کے لیے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"لوڈ ہو رہی ہے"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"صارف کی نئی پروفائل لوڈ ہو رہی ہے (<xliff:g id="FROM_USER">%1$d</xliff:g> سے <xliff:g id="TO_USER">%2$d</xliff:g> کو)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-uz/strings.xml b/packages/CarSystemUI/res/values-uz/strings.xml deleted file mode 100644 index adef2add435f..000000000000 --- a/packages/CarSystemUI/res/values-uz/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Daq."</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Endi ovozni tanish Bluetooth qurilma ulanganda amalga oshadi"</string> - <string name="car_guest" msgid="318393171202663722">"Mehmon"</string> - <string name="start_guest_session" msgid="497784785761754874">"Mehmon"</string> - <string name="car_add_user" msgid="4067337059622483269">"Foydalanuvchi kiritish"</string> - <string name="car_new_user" msgid="6637442369728092473">"Yangi foydalanuvchi"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yangi profil kiritilgach, uni sozlash lozim."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Qurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Yuklanmoqda"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Foydalanuvchi profili yuklanmoqda (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-vi/strings.xml b/packages/CarSystemUI/res/values-vi/strings.xml deleted file mode 100644 index 616b48fd17b6..000000000000 --- a/packages/CarSystemUI/res/values-vi/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Tối thiểu"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Tối đa"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Thiết bị Bluetooth được kết nối đang xử lý vấn đề nhận dạng giọng nói"</string> - <string name="car_guest" msgid="318393171202663722">"Khách"</string> - <string name="start_guest_session" msgid="497784785761754874">"Khách"</string> - <string name="car_add_user" msgid="4067337059622483269">"Thêm người dùng"</string> - <string name="car_new_user" msgid="6637442369728092473">"Người dùng mới"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Khi bạn thêm một người dùng mới, người đó cần thiết lập không gian của mình."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Bất kỳ người dùng nào cũng có thể cập nhật ứng dụng cho tất cả những người dùng khác."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Đang tải"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Đang tải hồ sơ người dùng (từ <xliff:g id="FROM_USER">%1$d</xliff:g> sang <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-zh-rCN/strings.xml b/packages/CarSystemUI/res/values-zh-rCN/strings.xml deleted file mode 100644 index 6dc37382b25c..000000000000 --- a/packages/CarSystemUI/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"现在由已连接的蓝牙设备处理语音识别操作"</string> - <string name="car_guest" msgid="318393171202663722">"访客"</string> - <string name="start_guest_session" msgid="497784785761754874">"访客"</string> - <string name="car_add_user" msgid="4067337059622483269">"添加用户"</string> - <string name="car_new_user" msgid="6637442369728092473">"新用户"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"当您添加新用户时,该用户需要自行设置个人空间。"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"任何用户均可为所有其他用户更新应用。"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"正在加载"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在加载用户(从 <xliff:g id="FROM_USER">%1$d</xliff:g> 到 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-zh-rHK/strings.xml b/packages/CarSystemUI/res/values-zh-rHK/strings.xml deleted file mode 100644 index 00ebd3219ea3..000000000000 --- a/packages/CarSystemUI/res/values-zh-rHK/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"現在由已連線的藍牙裝置處理語音辨識作業"</string> - <string name="car_guest" msgid="318393171202663722">"訪客"</string> - <string name="start_guest_session" msgid="497784785761754874">"訪客"</string> - <string name="car_add_user" msgid="4067337059622483269">"新增使用者"</string> - <string name="car_new_user" msgid="6637442369728092473">"新使用者"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"新增的使用者需要自行設定個人空間。"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"任何使用者都可以為所有其他使用者更新應用程式。"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"正在載入"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在載入使用者 (由 <xliff:g id="FROM_USER">%1$d</xliff:g> 至 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-zh-rTW/strings.xml b/packages/CarSystemUI/res/values-zh-rTW/strings.xml deleted file mode 100644 index 96d6a1d201be..000000000000 --- a/packages/CarSystemUI/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"現在由已連線的藍牙裝置處理語音辨識作業"</string> - <string name="car_guest" msgid="318393171202663722">"訪客"</string> - <string name="start_guest_session" msgid="497784785761754874">"訪客"</string> - <string name="car_add_user" msgid="4067337059622483269">"新增使用者"</string> - <string name="car_new_user" msgid="6637442369728092473">"新使用者"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"新使用者必須自行設定個人空間。"</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"任何使用者都能為所有其他使用者更新應用程式。"</string> - <string name="car_loading_profile" msgid="4507385037552574474">"載入中"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在載入使用者 (從 <xliff:g id="FROM_USER">%1$d</xliff:g> 到 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CarSystemUI/res/values-zu/strings.xml b/packages/CarSystemUI/res/values-zu/strings.xml deleted file mode 100644 index b835f9a69bde..000000000000 --- a/packages/CarSystemUI/res/values-zu/strings.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright (c) 2018 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="hvac_min_text" msgid="8167124789068494624">"Okuncane"</string> - <string name="hvac_max_text" msgid="3669693372074755551">"Okuningi"</string> - <string name="voice_recognition_toast" msgid="1149934534584052842">"Ukubonwa kwezwi manje kuphethwe idivayisi exhunyiwe ye-Bluetooth"</string> - <string name="car_guest" msgid="318393171202663722">"Isihambeli"</string> - <string name="start_guest_session" msgid="497784785761754874">"Isihambeli"</string> - <string name="car_add_user" msgid="4067337059622483269">"Engeza umsebenzisi"</string> - <string name="car_new_user" msgid="6637442369728092473">"Umsebenzisi omusha"</string> - <string name="user_add_user_message_setup" msgid="1035578846007352323">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha izikhala zakhe."</string> - <string name="user_add_user_message_update" msgid="7061671307004867811">"Noma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza zabanye abasebenzisi."</string> - <string name="car_loading_profile" msgid="4507385037552574474">"Iyalayisha"</string> - <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ilayisha umsebenzisi (kusuka ku-<xliff:g id="FROM_USER">%1$d</xliff:g> kuya ku-<xliff:g id="TO_USER">%2$d</xliff:g>)"</string> -</resources> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 16ef59f201f1..e501e1269aeb 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -18,6 +18,8 @@ package com.android.companiondevicemanager; import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress; +import static java.util.Objects.requireNonNull; + import android.app.Activity; import android.companion.CompanionDeviceManager; import android.content.Intent; @@ -117,6 +119,11 @@ public class DeviceChooserActivity extends Activity { } @Override + public String getCallingPackage() { + return requireNonNull(getService().mRequest.getCallingPackage()); + } + + @Override public void setTitle(CharSequence title) { final TextView titleView = findViewById(R.id.title); final int padding = getPadding(getResources()); diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml index fa738734c598..1049c3ca6b93 100644 --- a/packages/PackageInstaller/res/values-es/strings.xml +++ b/packages/PackageInstaller/res/values-es/strings.xml @@ -56,8 +56,8 @@ <string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta aplicación?"</string> <string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta aplicación para "<b>"todos"</b>" los usuarios? La aplicación y sus datos se borrarán de "<b>"todos"</b>" los usuarios del dispositivo."</string> <string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta aplicación para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string> - <string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string> - <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string> + <string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres sustituir esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string> + <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres sustituir esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string> <string name="uninstall_keep_data" msgid="7002379587465487550">"Mantener <xliff:g id="SIZE">%1$s</xliff:g> de datos de aplicaciones."</string> <string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalaciones en curso"</string> <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalaciones fallidas"</string> diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml index d3a958922d1c..108c86fe8369 100644 --- a/packages/PackageInstaller/res/values-nl/strings.xml +++ b/packages/PackageInstaller/res/values-nl/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name" msgid="7488448184431507488">"Pakket-installatie"</string> <string name="install" msgid="711829760615509273">"Installeren"</string> - <string name="done" msgid="6632441120016885253">"Klaar"</string> + <string name="done" msgid="6632441120016885253">"Gereed"</string> <string name="cancel" msgid="1018267193425558088">"Annuleren"</string> <string name="installing" msgid="4921993079741206516">"Installeren…"</string> <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> installeren…"</string> diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml index 20a1ee369547..8c89ce9ca0eb 100644 --- a/packages/PackageInstaller/res/values-or/strings.xml +++ b/packages/PackageInstaller/res/values-or/strings.xml @@ -19,7 +19,7 @@ <string name="app_name" msgid="7488448184431507488">"ପ୍ୟାକେଜ୍ ଇନଷ୍ଟଲର୍"</string> <string name="install" msgid="711829760615509273">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string> <string name="done" msgid="6632441120016885253">"ହୋଇଗଲା"</string> - <string name="cancel" msgid="1018267193425558088">"ବାତିଲ୍ କରନ୍ତୁ"</string> + <string name="cancel" msgid="1018267193425558088">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string> <string name="installing" msgid="4921993079741206516">"ଇନଷ୍ଟଲ୍ କରାଯାଉଛି…"</string> <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି…"</string> <string name="install_done" msgid="5987363587661783896">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇଗଲା।"</string> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index 6fbee16e3dae..861a8ef0a910 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -105,7 +105,8 @@ public class InstallStart extends Activity { } Intent nextActivity = new Intent(intent); - nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT + | Intent.FLAG_GRANT_READ_URI_PERMISSION); // The the installation source as the nextActivity thinks this activity is the source, hence // set the originating UID and sourceInfo explicitly diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index be778e92787e..94829b506f95 100755 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -17,6 +17,7 @@ package com.android.packageinstaller; import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid; @@ -87,6 +88,8 @@ public class UninstallerActivity extends Activity { @Override public void onCreate(Bundle icicle) { + getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + // Never restore any state, esp. never create any fragments. The data in the fragment might // be stale, if e.g. the app was uninstalled while the activity was destroyed. super.onCreate(null); diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml index a346cb2c1b2d..98687b40af16 100644 --- a/packages/PrintSpooler/res/values-ca/strings.xml +++ b/packages/PrintSpooler/res/values-ca/strings.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="4469836075319831821">"Gestor de cues d\'impressió"</string> + <string name="app_label" msgid="4469836075319831821">"Gest. cues impr."</string> <string name="more_options_button" msgid="2243228396432556771">"Més opcions"</string> <string name="label_destination" msgid="9132510997381599275">"Destinació"</string> <string name="label_copies" msgid="3634531042822968308">"Còpies"</string> diff --git a/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml index 5b12fc586ef9..7ab3abcf7540 100644 --- a/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"المساعدة والملاحظات والآراء"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"المساعدة والتعليقات"</string> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml index 150020cb17c5..759da1d0b021 100644 --- a/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml index 150020cb17c5..759da1d0b021 100644 --- a/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml index 150020cb17c5..759da1d0b021 100644 --- a/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-es/strings.xml b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml index 97e3559914a2..97ff5efc6401 100644 --- a/packages/SettingsLib/HelpUtils/res/values-es/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"Ayuda y comentarios"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"Ayuda y sugerencias"</string> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-te/strings.xml b/packages/SettingsLib/HelpUtils/res/values-te/strings.xml index 82c8613b5c8c..ea66717b1e87 100644 --- a/packages/SettingsLib/HelpUtils/res/values-te/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-te/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"సహాయం & ఫీడ్బ్యాక్"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"సహాయం & అభిప్రాయం"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml index 42cf76173a72..e26af95395a0 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"يفعِّل المشرف هذا الإعداد."</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"فعَّل المشرف هذا الإعداد."</string> <string name="disabled_by_admin" msgid="4023569940620832713">"أوقف المشرف هذا الإعداد."</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml index 7f10edf158b6..3a0bc2d2eb77 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml @@ -18,5 +18,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Aktiveret af administratoren"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktiveret af administrator"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktiveret af administratoren"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml index 351f16cb1a24..4a6f73f0fcef 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"Habilitado por el administrador"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"Inhabilitado por el administrador"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"Habilitada por el administrador"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"Inhabilitada por el administrador"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml index 2a881247c3af..aaf607f6f3ce 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml @@ -18,5 +18,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Administratzaileak gaitu egin du"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"Administratzaileak desgaitu du"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"Administratzaileak desgaitu egin du"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml index 9c39f98aab17..aaf9116bc9d5 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"توسط سرپرست فعال شده"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"توسط سرپرست غیرفعال شده"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"فعالشده توسط سرپرست"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"غیرفعالشده توسط سرپرست"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml index 490efd099569..7fcdbdfa7dab 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"管理者によって有効にされています"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"管理者により無効にされています"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"管理者が有効にしました"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"管理者が無効にしました"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml index 9c225f92f3bb..d4bac70ac4e7 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"अॅडमिनने सुरू केलेले"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"प्रशासकाने सुरू केलेले"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"प्रशासकाने बंद केलेले"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml index 4ce6460f8b89..6b1f2590f8e2 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"ଆଡମିନଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"ଆଡମିନଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml index 908e2fbbff5b..5cf0b29e14ff 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"Ativado pelo administrador"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"Desativado pelo administrador"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"Ativada pelo administrador"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"Desativada pelo administrador"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml index 8f17dc5ec1e8..2da347c4454f 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"అడ్మిన్ ఎనేబుల్ చేశారు"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"అడ్మిన్ డిజేబుల్ చేశారు"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"నిర్వాహకులు ప్రారంభించారు"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"నిర్వాహకులు నిలిపివేసారు"</string> </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml index 2c37652c850e..f664bb444bc1 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml @@ -18,5 +18,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="enabled_by_admin" msgid="6630472777476410137">"Do quản trị viên bật"</string> - <string name="disabled_by_admin" msgid="4023569940620832713">"Đã bị quản trị viên vô hiệu hóa"</string> + <string name="disabled_by_admin" msgid="4023569940620832713">"Bị quản trị viên tắt"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-be/strings.xml b/packages/SettingsLib/SearchWidget/res/values-be/strings.xml index c72f8199f12e..4fc722faba52 100644 --- a/packages/SettingsLib/SearchWidget/res/values-be/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-be/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Пошук налад"</string> + <string name="search_menu" msgid="1914043873178389845">"Налады пошуку"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml index d50436a29ac1..6f5ab78b304b 100644 --- a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Αναζήτηση στις ρυθμίσεις"</string> + <string name="search_menu" msgid="1914043873178389845">"Ρυθμίσεις αναζήτησης"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml b/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml index 9b735fece386..ed549db3c113 100644 --- a/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-es-rUS/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Buscar configuraciones"</string> + <string name="search_menu" msgid="1914043873178389845">"Buscar en la configuración"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml index 2c9aaa5e9f95..fa5f9bdfe07b 100644 --- a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"تنظیمات جستجو"</string> + <string name="search_menu" msgid="1914043873178389845">"جستجوی تنظیمات"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fr-rCA/strings.xml index 9977138f2079..6b2364d04cc6 100644 --- a/packages/SettingsLib/SearchWidget/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-fr-rCA/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Rechercher dans les paramètres"</string> + <string name="search_menu" msgid="1914043873178389845">"Paramètres de recherche"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-hi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hi/strings.xml index 88c38316948a..975c320f9dba 100644 --- a/packages/SettingsLib/SearchWidget/res/values-hi/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-hi/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"सेटिंग में खोजें"</string> + <string name="search_menu" msgid="1914043873178389845">"खोज की सेटिंग"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml index 34cb8e0fda38..9d83396689bd 100644 --- a/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Pretražite postavke"</string> + <string name="search_menu" msgid="1914043873178389845">"Pretraži postavke"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml index b68b792acc32..8fa5a84acd79 100644 --- a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Որոնեք կարգավորումներ"</string> + <string name="search_menu" msgid="1914043873178389845">"Որոնման կարգավորումներ"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-in/strings.xml b/packages/SettingsLib/SearchWidget/res/values-in/strings.xml index ccf11d26273c..edf51cc601ac 100644 --- a/packages/SettingsLib/SearchWidget/res/values-in/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-in/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Telusuri setelan"</string> + <string name="search_menu" msgid="1914043873178389845">"Setelan penelusuran"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-is/strings.xml b/packages/SettingsLib/SearchWidget/res/values-is/strings.xml index 3378c84d7e08..7ab103b476f3 100644 --- a/packages/SettingsLib/SearchWidget/res/values-is/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-is/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Leita í stillingum"</string> + <string name="search_menu" msgid="1914043873178389845">"Leitarstillingar"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml index 09a285b7452f..8c7dd6fe3ec6 100644 --- a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਖੋਜੋ"</string> + <string name="search_menu" msgid="1914043873178389845">"ਖੋਜ ਸੈਟਿੰਗਾਂ"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml index 5fe116e86f94..85a8d7342827 100644 --- a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Pesquisar nas definições"</string> + <string name="search_menu" msgid="1914043873178389845">"Pesquisa de definições"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml index 354941d39e12..a5313210a6f9 100644 --- a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Kërko te cilësimet"</string> + <string name="search_menu" msgid="1914043873178389845">"Cilësimet e kërkimit"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml index 14b7b2f62eee..111cf5a15dba 100644 --- a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Maghanap sa mga setting"</string> + <string name="search_menu" msgid="1914043873178389845">"Mga setting ng paghahanap"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml index 560ac1359e5a..dfd66b28aa7a 100644 --- a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Пошук налаштувань"</string> + <string name="search_menu" msgid="1914043873178389845">"Налаштування пошуку"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml index 90daf11c712d..cb1a75a616f5 100644 --- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Tìm trong thông tin cài đặt"</string> + <string name="search_menu" msgid="1914043873178389845">"Tìm kiếm trong các mục cài đặt"</string> </resources> diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml index b19cde4f2778..a131a3b1ad91 100644 --- a/packages/SettingsLib/res/values-bn/arrays.xml +++ b/packages/SettingsLib/res/values-bn/arrays.xml @@ -40,7 +40,7 @@ <item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এর সাথে কানেক্ট হচ্ছে…"</item> <item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> দিয়ে যাচাইকরণ করা হচ্ছে..."</item> <item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে আইপি অ্যাড্রেস জানা হচ্ছে…"</item> - <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-এ কানেক্ট হয়েছে"</item> + <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে কানেক্ট হয়েছে"</item> <item msgid="7445993821842009653">"স্থগিত করা হয়েছে"</item> <item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে ডিসকানেক্ট হচ্ছে…"</item> <item msgid="699832486578171722">"ডিসকানেক্ট করা হয়েছে"</item> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index a5567d74b7b5..15ebfb88ea76 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -481,8 +481,8 @@ <string name="status_unavailable" msgid="5279036186589861608">"অনুপলব্ধ"</string> <string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC র্যান্ডমাইজ করা হয়েছে"</string> <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139"> - <item quantity="one">%1$dটি ডিভাইস কানেক্ট রয়েছে</item> - <item quantity="other">%1$dটি ডিভাইস কানেক্ট রয়েছে</item> + <item quantity="one">%1$dটি ডিভাইস কানেক্ট</item> + <item quantity="other">%1$dটি ডিভাইস কানেক্ট</item> </plurals> <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"আরও বেশি।"</string> <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"আরও কম।"</string> diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml index fb4340db4cf8..6489cefdc551 100644 --- a/packages/SettingsLib/res/values-bs/arrays.xml +++ b/packages/SettingsLib/res/values-bs/arrays.xml @@ -187,7 +187,7 @@ <item msgid="97587758561106269">"Isključeno"</item> <item msgid="7126170197336963369">"Međuspremnici svih zapisnika"</item> <item msgid="7167543126036181392">"Međuspremnici svih zapisnika osim radija"</item> - <item msgid="5135340178556563979">"samo međumemorija zapisnika kernela"</item> + <item msgid="5135340178556563979">"samo međuspremnik zapisnika kernela"</item> </string-array> <string-array name="window_animation_scale_entries"> <item msgid="2675263395797191850">"Animacija isključena"</item> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 736c0f75d377..fd2635a9cbe5 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -394,7 +394,7 @@ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktibo. Aldatzeko, sakatu hau."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Egonean moduko aplikazioaren egoera: <xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string> - <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string> + <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu unean abian diren zerbitzuak"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ezarri WebView inplementazioa"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Jada ez dago erabilgarri aukera hori. Saiatu berriro."</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index d965b1209eeb..1407a50d7629 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -37,7 +37,7 @@ <string name="wifi_no_internet" msgid="1774198889176926299">"Sen acceso a Internet"</string> <string name="saved_network" msgid="7143698034077223645">"Gardada por <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectouse automaticamente a través de %1$s"</string> - <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de redes"</string> + <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de rede"</string> <string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string> <string name="connected_via_app" msgid="3532267661404276584">"Wifi conectada a través de <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="available_via_passpoint" msgid="1716000261192603682">"Dispoñible a través de %1$s"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 16f470d3cd91..889857ab8829 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -481,8 +481,8 @@ <string name="status_unavailable" msgid="5279036186589861608">"અનુપલબ્ધ"</string> <string name="wifi_status_mac_randomized" msgid="466382542497832189">"MACને રેન્ડમ કરેલ છે"</string> <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139"> - <item quantity="one">%1$d ડિવાઇસ કનેક્ટ કર્યું</item> - <item quantity="other">%1$d ડિવાઇસ કનેક્ટ કર્યા</item> + <item quantity="one">%1$d ઉપકરણ કનેક્ટ કર્યું</item> + <item quantity="other">%1$d ઉપકરણો કનેક્ટ કર્યા</item> </plurals> <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"વધુ સમય."</string> <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ઓછો સમય."</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index a70a0057410d..24153b9a04df 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -519,7 +519,7 @@ <string name="status_unavailable" msgid="5279036186589861608">"अनुपलब्ध"</string> <string name="wifi_status_mac_randomized" msgid="466382542497832189">"एमएसी पता रैंडम पर सेट है"</string> <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139"> - <item quantity="one">%1$d डिवाइस जुड़ा है</item> + <item quantity="one">%1$d डिवाइस जुड़े हैं</item> <item quantity="other">%1$d डिवाइस जुड़े हैं</item> </plurals> <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ज़्यादा समय."</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index f4015e8267af..61433be1549c 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -145,7 +145,7 @@ <string name="data_usage_ota" msgid="7984667793701597001">"Rendszerfrissítések"</string> <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB-megosztás"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Hordozható hotspot"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth-megosztás"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth megosztása"</string> <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Megosztás"</string> <string name="tether_settings_title_all" msgid="8910259483383010470">"Megosztás és hotspot"</string> <string name="managed_user_title" msgid="449081789742645723">"Összes munkaalkalmazás"</string> diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml index 141ce3990800..a2de6dfc7387 100644 --- a/packages/SettingsLib/res/values-hy/arrays.xml +++ b/packages/SettingsLib/res/values-hy/arrays.xml @@ -55,7 +55,7 @@ </string-array> <string-array name="hdcp_checking_summaries"> <item msgid="4045840870658484038">"Երբեք չօգտագործել HDCP ստուգումը"</item> - <item msgid="8254225038262324761">"Օգտագործել HDCP-ը՝ միայն DRM-ի բովանդակությունը ստուգելու համար"</item> + <item msgid="8254225038262324761">"Օգտագործել HDCP-ը` միայն DRM-ի բովանդակությունը ստուգելու համար"</item> <item msgid="6421717003037072581">"Միշտ օգտագործել HDCP ստուգումը"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 333a73503068..2e39f2cfdcb7 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -57,7 +57,7 @@ <string name="osu_sign_up_complete" msgid="7640183358878916847">"Գրանցումն ավարտված է: Միացում…"</string> <string name="speed_label_very_slow" msgid="8526005255731597666">"Շատ դանդաղ"</string> <string name="speed_label_slow" msgid="6069917670665664161">"Դանդաղ"</string> - <string name="speed_label_okay" msgid="1253594383880810424">"Լավ"</string> + <string name="speed_label_okay" msgid="1253594383880810424">"Հաստատել"</string> <string name="speed_label_medium" msgid="9078405312828606976">"Միջին"</string> <string name="speed_label_fast" msgid="2677719134596044051">"Արագ"</string> <string name="speed_label_very_fast" msgid="8215718029533182439">"Շատ արագ"</string> @@ -339,7 +339,7 @@ <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"Թարմացվելիս ընդգծել սարքաշարի ծածկույթները կանաչ գույնով"</string> <string name="debug_hw_overdraw" msgid="8944851091008756796">"Վրիպազերծել GPU գերազանցումները"</string> <string name="disable_overlays" msgid="4206590799671557143">"Կասեցնել HW վրադրումները"</string> - <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն՝ էկրանի կազմման համար"</string> + <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն` էկրանի կազմման համար"</string> <string name="simulate_color_space" msgid="1206503300335835151">"Նմանակել գունատարածքը"</string> <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Ակտիվացնել OpenGL հետքերը"</string> <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Անջատել USB աուդիո երթուղումը"</string> @@ -487,7 +487,7 @@ <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Ավելացնել ժամանակը:"</string> <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Պակասեցնել ժամանակը:"</string> <string name="cancel" msgid="5665114069455378395">"Չեղարկել"</string> - <string name="okay" msgid="949938843324579502">"Եղավ"</string> + <string name="okay" msgid="949938843324579502">"Հաստատել"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Միացնել"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Միացրեք «Չանհանգստացնել» ռեժիմը"</string> <string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"Երբեք"</string> diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml index d20bf38024ab..e73febcb1aa4 100644 --- a/packages/SettingsLib/res/values-in/arrays.xml +++ b/packages/SettingsLib/res/values-in/arrays.xml @@ -40,7 +40,7 @@ <item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> <item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> <item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> - <item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item> + <item msgid="1043944043827424501">"Tersambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item> <item msgid="7445993821842009653">"Ditangguhkan"</item> <item msgid="1175040558087735707">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> <item msgid="699832486578171722">"Sambungan terputus"</item> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 792b75ae09da..b75fa357b938 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -156,7 +156,7 @@ <string name="launch_defaults_none" msgid="8049374306261262709">"Tidak ada setelan default"</string> <string name="tts_settings" msgid="8130616705989351312">"Setelan text-to-speech"</string> <string name="tts_settings_title" msgid="7602210956640483039">"Keluaran text-to-speech"</string> - <string name="tts_default_rate_title" msgid="3964187817364304022">"Kecepatan ucapan"</string> + <string name="tts_default_rate_title" msgid="3964187817364304022">"Laju bicara"</string> <string name="tts_default_rate_summary" msgid="3781937042151716987">"Kecepatan teks diucapkan"</string> <string name="tts_default_pitch_title" msgid="6988592215554485479">"Tinggi nada"</string> <string name="tts_default_pitch_summary" msgid="9132719475281551884">"Memengaruhi nada ucapan yang disintesis"</string> diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml index fd2f2c1818d6..0bca8ea75212 100644 --- a/packages/SettingsLib/res/values-it/arrays.xml +++ b/packages/SettingsLib/res/values-it/arrays.xml @@ -22,13 +22,13 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string-array name="wifi_status"> <item msgid="1596683495752107015"></item> - <item msgid="3288373008277313483">"Scansione in corso…"</item> - <item msgid="6050951078202663628">"Connessione…"</item> - <item msgid="8356618438494652335">"Autenticazione…"</item> - <item msgid="2837871868181677206">"Acquisizione indirizzo IP…"</item> + <item msgid="3288373008277313483">"Scansione in corso..."</item> + <item msgid="6050951078202663628">"Connessione..."</item> + <item msgid="8356618438494652335">"Autenticazione..."</item> + <item msgid="2837871868181677206">"Acquisizione indirizzo IP..."</item> <item msgid="4613015005934755724">"Connessa"</item> <item msgid="3763530049995655072">"Sospesa"</item> - <item msgid="7852381437933824454">"Disconnessione…"</item> + <item msgid="7852381437933824454">"Disconnessione..."</item> <item msgid="5046795712175415059">"Disconnessa"</item> <item msgid="2473654476624070462">"Operazione non riuscita"</item> <item msgid="9146847076036105115">"Bloccato"</item> @@ -36,13 +36,13 @@ </string-array> <string-array name="wifi_status_with_ssid"> <item msgid="5969842512724979061"></item> - <item msgid="1818677602615822316">"Scansione in corso…"</item> - <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> - <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> - <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> + <item msgid="1818677602615822316">"Scansione in corso..."</item> + <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item> + <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item> + <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item> <item msgid="1043944043827424501">"Connessa a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item> <item msgid="7445993821842009653">"Sospesa"</item> - <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> + <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item> <item msgid="699832486578171722">"Disconnessa"</item> <item msgid="522383512264986901">"Operazione non riuscita"</item> <item msgid="3602596701217484364">"Bloccato"</item> diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml index d166c179757c..2966f09c6c1b 100644 --- a/packages/SettingsLib/res/values-ja/arrays.xml +++ b/packages/SettingsLib/res/values-ja/arrays.xml @@ -40,7 +40,7 @@ <item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続中..."</item> <item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>による認証中..."</item> <item msgid="4287401332778341890">"IPアドレスを<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から取得中..."</item> - <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> に接続済み"</item> + <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続しました"</item> <item msgid="7445993821842009653">"保留中"</item> <item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から切断中..."</item> <item msgid="699832486578171722">"切断されました"</item> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 895e450a59c5..2070056fad14 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -390,8 +390,8 @@ <item msgid="1282170165150762976">"Санарип мазмун үчүн оптималдаштырылган түстөр"</item> </string-array> <string name="inactive_apps_title" msgid="5372523625297212320">"Көшүү режиминдеги колдонмолор"</string> - <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Күйгүзүү үчүн басып коюңуз."</string> - <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Өчүрүү үчүн басып коюңуз."</string> + <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Которуштуруу үчүн таптап коюңуз."</string> + <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Көшүү режиминдеги колдонмонун абалы:<xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 6db2404d95eb..ae2df9a9e76f 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -204,10 +204,10 @@ <string name="tethering_settings_not_available" msgid="266821736434699780">"Поставките за спојување не се достапни за овој корисник"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Поставките за името на пристапната точка не се достапни за овој корисник"</string> <string name="enable_adb" msgid="8072776357237289039">"Отстранување грешки на USB"</string> - <string name="enable_adb_summary" msgid="3711526030096574316">"Режим за отстранување грешки кога е поврзано USB"</string> + <string name="enable_adb_summary" msgid="3711526030096574316">"Режим на отстранување грешки кога е поврзано USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Отповикај овластувања за отстранување грешки од USB"</string> <string name="enable_adb_wireless" msgid="6973226350963971018">"Безжично отстранување грешки"</string> - <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим за отстранување грешки кога е поврзано Wi‑Fi"</string> + <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим на отстранување грешки кога е поврзано Wi‑Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Грешка"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Безжично отстранување грешки"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да ги гледате и користите достапните уреди, вклучете го безжичното отстранување грешки"</string> diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml index 43e4e6664d1f..5d79e80608d0 100644 --- a/packages/SettingsLib/res/values-ne/arrays.xml +++ b/packages/SettingsLib/res/values-ne/arrays.xml @@ -238,7 +238,7 @@ </string-array> <string-array name="show_non_rect_clip_entries"> <item msgid="2482978351289846212">"बन्द"</item> - <item msgid="3405519300199774027">"गैर आयातकार क्षेत्र निलो रङमा कोर्नुहोस्"</item> + <item msgid="3405519300199774027">"गैर आयातकार क्षेत्र नीलो रङमा कोर्नुहोस्"</item> <item msgid="1212561935004167943">"हाइलाइट परीक्षण चित्र कोर्ने आदेशहरू हरियोमा"</item> </string-array> <string-array name="track_frame_time_entries"> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 79bb43db9d05..e11f02d0bc04 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -143,9 +143,9 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"हटाइएका अनुप्रयोगहरू"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"अनुप्रयोगहरू र प्रयोगकर्ताहरू हटाइयो।"</string> <string name="data_usage_ota" msgid="7984667793701597001">"प्रणालीसम्बन्धी अद्यावधिकहरू"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB टेदर गर्दै"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB टेथर गर्दै"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"पोर्टेबल हटस्पट"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ब्लुटुथ टेदर गर्दै"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ब्लुटुथ टेथर गर्दै"</string> <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"टेदर गर्दै"</string> <string name="tether_settings_title_all" msgid="8910259483383010470">"टेदर गर्ने र पोर्टेबल हटस्पट"</string> <string name="managed_user_title" msgid="449081789742645723">"कार्य प्रोफाइलका सबै अनुप्रयोगहरू"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index a5714c3ba842..3ca705f71e18 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -143,11 +143,11 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Programu zilizoondolewa"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Watumiaji na programu ziilizoondolewa"</string> <string name="data_usage_ota" msgid="7984667793701597001">"Masasisho ya mfumo"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"Sambaza mtandao kwa USB"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"Shiriki intaneti kwa USB"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Intaneti ya kusambazwa"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Sambaza mtandao kwa Bluetooth"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Kusambaza mtandao"</string> - <string name="tether_settings_title_all" msgid="8910259483383010470">"Kushiriki na kusambaza mtandao"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Shiriki intaneti kwa Bluetooth"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Inazuia"</string> + <string name="tether_settings_title_all" msgid="8910259483383010470">"Kushiriki na kusambaza intaneti"</string> <string name="managed_user_title" msgid="449081789742645723">"Programu zote za kazini"</string> <string name="user_guest" msgid="6939192779649870792">"Mgeni"</string> <string name="unknown" msgid="3544487229740637809">"Haijulikani"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index aa0da1231bed..e34c548b68e2 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -143,7 +143,7 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"แอปพลิเคชันที่นำออก"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"แอปพลิเคชันและผู้ใช้ที่นำออก"</string> <string name="data_usage_ota" msgid="7984667793701597001">"การอัปเดตระบบ"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"เชื่อมต่อเน็ตผ่าน USB"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"ปล่อยสัญญาณผ่าน USB"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"ฮอตสปอตแบบพกพาได้"</string> <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ปล่อยสัญญาณบลูทูธ"</string> <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"การปล่อยสัญญาณ"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 03161d051342..fb695e50ed7c 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1100,6 +1100,8 @@ <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until charged</string> <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until charged</string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when charge been limited --> + <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Optimizing for battery health</string> <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> <string name="battery_info_status_unknown">Unknown</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index b2808061586b..9e59ce3ea166 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -14,6 +14,9 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.location.LocationManager; @@ -303,6 +306,36 @@ public class Utils { } /** + * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but + * preserves the alpha for a given drawable + * @param color + * @return a color matrix that uses the source alpha and given color + */ + public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) { + int r = Color.red(color); + int g = Color.green(color); + int b = Color.blue(color); + + ColorMatrix cm = new ColorMatrix(new float[] { + 0, 0, 0, 0, r, + 0, 0, 0, 0, g, + 0, 0, 0, 0, b, + 0, 0, 0, 1, 0 }); + + return cm; + } + + /** + * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics + * + * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on + * the source alpha + */ + public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) { + return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color)); + } + + /** * Determine whether a package is a "system package", in which case certain things (like * disabling notifications or disabling the package altogether) should be disallowed. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index a5b5312707d0..5fa04f93e993 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -108,6 +108,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) private val fillColorStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).also { p -> p.color = frameColor + p.alpha = 255 p.isDither = true p.strokeWidth = 5f p.style = Paint.Style.STROKE @@ -145,7 +146,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // Only used if dualTone is set to true private val dualToneBackgroundFill = Paint(Paint.ANTI_ALIAS_FLAG).also { p -> p.color = frameColor - p.alpha = 255 + p.alpha = 85 // ~0.3 alpha by default p.isDither = true p.strokeWidth = 0f p.style = Paint.Style.FILL_AND_STROKE diff --git a/packages/SettingsProvider/res/values-fa/strings.xml b/packages/SettingsProvider/res/values-fa/strings.xml index 946e2c07c576..cc0b55728310 100644 --- a/packages/SettingsProvider/res/values-fa/strings.xml +++ b/packages/SettingsProvider/res/values-fa/strings.xml @@ -19,7 +19,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="4567566098528588863">"تنظیم محل فضای ذخیرهسازی"</string> + <string name="app_label" msgid="4567566098528588863">"تنظیم محل ذخیره"</string> <string name="wifi_softap_config_change" msgid="5688373762357941645">"تنظیمات نقطه اتصال تغییر کرده است"</string> <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"برای مشاهده جزئیات ضربه بزنید"</string> </resources> diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml index dc55986faf29..7d04eeb9165f 100644 --- a/packages/Shell/res/values-it/strings.xml +++ b/packages/Shell/res/values-it/strings.xml @@ -21,7 +21,7 @@ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string> <string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string> <string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string> - <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi…"</string> + <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string> <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"La segnalazione di bug comparirà a breve sul telefono"</string> <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Seleziona per condividere la segnalazione di bug"</string> <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string> diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 65e3f0dbd176..6d86a78360d8 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -112,7 +112,7 @@ <string name="kg_pin_accepted" msgid="1625501841604389716">"تم قبول الرمز"</string> <string name="keyguard_carrier_default" msgid="6359808469637388586">"لا تتوفر خدمة."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"تبديل أسلوب الإدخال"</string> - <string name="airplane_mode" msgid="2528005343938497866">"وضع الطيران"</string> + <string name="airplane_mode" msgid="2528005343938497866">"وضع الطائرة"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"يجب رسم النقش بعد إعادة تشغيل الجهاز"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"يجب إدخال كلمة المرور بعد إعادة تشغيل الجهاز"</string> diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index ea07c3db4354..d63c23f4d1f6 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Şifrənizi daxil edin"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Yanlış PIN kod."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Yanlış Kart."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Enerji yığılıb"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Enerji yığdı"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz şəkildə batareya yığır"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Enerji yığır"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sürətlə enerji yığır"</string> diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 0754681215cc..ce323c7f65a7 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduce tu contraseña"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"El código PIN es incorrecto."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Tarjeta no válida."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Cargada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sin cables"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string> diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index 46079810aee4..420649eeca60 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduce o contrasinal"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorrecto"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"A tarxeta non é válida."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Cargada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sen fíos"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 85b2a4726fa2..875d8d51c50b 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Masukkan sandi"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Kode PIN salah."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kartu Tidak Valid"</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Terisi penuh"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Terisi"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya secara nirkabel"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan cepat"</string> diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index e1c9ee8b7d34..16767d1771fe 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -48,7 +48,7 @@ <string name="keyguard_permanent_disabled_sim_instructions" msgid="2490584154727897806">"La scheda SIM è stata disattivata definitivamente.\n Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string> <string name="keyguard_sim_locked_message" msgid="4343544458476911044">"La SIM è bloccata."</string> <string name="keyguard_sim_puk_locked_message" msgid="6253830777745450550">"La SIM è bloccata tramite PUK."</string> - <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM…"</string> + <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM..."</string> <string name="keyguard_accessibility_pin_area" msgid="7403009340414014734">"Area PIN"</string> <string name="keyguard_accessibility_password" msgid="3524161948484801450">"Password del dispositivo"</string> <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Area PIN SIM"</string> @@ -77,7 +77,7 @@ <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"La SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" non è attiva al momento. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string> <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Inserisci il codice PIN desiderato"</string> <string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Conferma il codice PIN desiderato"</string> - <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM…"</string> + <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM..."</string> <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Il PIN deve essere di 4-8 numeri."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Il codice PUK dovrebbe avere almeno otto numeri."</string> <string name="kg_invalid_puk" msgid="1774337070084931186">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 62afd1e45df8..96972a7577cf 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -70,7 +70,7 @@ <string name="kg_pattern_instructions" msgid="5376036737065051736">"Өрнекті енгізіңіз"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN кодын енгізіңіз."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" үшін SIM PIN кодын енгізіңіз."</string> - <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Құрылғыны мобильдік байланыс қызметінсіз пайдалану үшін eSIM картасын өшіріңіз."</string> + <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Құрылығыны мобильдік байланыс қызметінсіз пайдалану үшін eSIM картасын өшіріңіз."</string> <string name="kg_pin_instructions" msgid="822353548385014361">"PIN кодын енгізіңіз"</string> <string name="kg_password_instructions" msgid="324455062831719903">"Кілтсөзді енгізіңіз"</string> <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. Толығырақ ақпаратты оператордан алыңыз."</string> diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index 52b7fab768c5..24b5c23a6732 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -100,7 +100,7 @@ <string name="kg_pin_accepted" msgid="1625501841604389716">"កូដត្រូវបានទទួលយក!"</string> <string name="keyguard_carrier_default" msgid="6359808469637388586">"គ្មានសេវាទេ។"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ប្ដូរវិធីបញ្ចូល"</string> - <string name="airplane_mode" msgid="2528005343938497866">"ពេលជិះយន្តហោះ"</string> + <string name="airplane_mode" msgid="2528005343938497866">"មុខងារពេលជិះយន្តហោះ"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index 848490ebb9b8..6ae5935fea1a 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -62,7 +62,7 @@ <string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"패턴을 잊음"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"잘못된 패턴"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"잘못된 비밀번호"</string> - <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 오류"</string> + <string name="kg_wrong_pin" msgid="4160978845968732624">"잘못된 PIN"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914"> <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요.</item> <item quantity="one">1초 후에 다시 시도하세요.</item> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index d868788a3eca..9675cc9d39b2 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -45,7 +45,7 @@ <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM-карта салыңыз."</string> <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта жок же ал окулбай калган. SIM-карта салыңыз."</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Жараксыз SIM-карта."</string> - <string name="keyguard_permanent_disabled_sim_instructions" msgid="2490584154727897806">"SIM картаңыз биротоло өчүрүлдү.\n Башка SIM-карта алыш үчүн зымсыз кызмат көрсөтүүчүгө кайрылыңыз."</string> + <string name="keyguard_permanent_disabled_sim_instructions" msgid="2490584154727897806">"SIM-картаңыз биротоло өчүрүлдү.\n Башка SIM-карта алыш үчүн зымсыз кызмат көрсөтүүчүгө кайрылыңыз."</string> <string name="keyguard_sim_locked_message" msgid="4343544458476911044">"SIM-карта кулпуланган."</string> <string name="keyguard_sim_puk_locked_message" msgid="6253830777745450550">"SIM-карта PUK-код менен кулпуланган."</string> <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"SIM-карта бөгөттөн чыгарылууда…"</string> @@ -80,7 +80,7 @@ <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"SIM-карта бөгөттөн чыгарылууда…"</string> <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4–8 сандан турган PIN-кодду териңиз."</string> <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код 8 же андан көп сандан турушу керек."</string> - <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK-кодду кайрадан туура киргизиңиз. Кайталанган аракеттер SIM картаны биротоло жараксыз кылат."</string> + <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK-кодду кайрадан туура киргизиңиз. Кайталанган аракеттер SIM-картаны биротоло жараксыз кылат."</string> <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Өтө көп графикалык ачкычты тартуу аракети болду"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string> @@ -98,7 +98,7 @@ <string name="kg_password_pin_failed" msgid="5136259126330604009">"SIM-картанын PIN-кодун ачуу кыйрады!"</string> <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-картанын PUK-кодун ачуу кыйрады!"</string> <string name="kg_pin_accepted" msgid="1625501841604389716">"Код кабыл алынды!"</string> - <string name="keyguard_carrier_default" msgid="6359808469637388586">"Интернет жок."</string> + <string name="keyguard_carrier_default" msgid="6359808469637388586">"Байланыш жок."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Киргизүү ыкмасын өзгөртүү"</string> <string name="airplane_mode" msgid="2528005343938497866">"Учак режими"</string> <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкычты тартуу талап кылынат"</string> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index ce05e38dca10..0cec32e9a90c 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -60,7 +60,7 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"कुनै त्रुटिका कारण यो eSIM लाई असक्षम पार्न सकिएन।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"प्रविष्टि गर्नुहोस्"</string> <string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"ढाँचा बिर्सनुभयो"</string> - <string name="kg_wrong_pattern" msgid="5907301342430102842">"प्याटर्न मिलेन"</string> + <string name="kg_wrong_pattern" msgid="5907301342430102842">"गलत ढाँचा"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"गलत पासवर्ड"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"गलत PIN"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914"> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 5094cf9983a1..9b6f857456d6 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -54,7 +54,7 @@ <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Miejsce na kod PIN karty SIM"</string> <string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"Miejsce na kod PUK karty SIM"</string> <string name="keyguard_accessibility_next_alarm" msgid="4492876946798984630">"Następny alarm ustawiony na: <xliff:g id="ALARM">%1$s</xliff:g>"</string> - <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuń"</string> + <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuwanie"</string> <string name="disable_carrier_button_text" msgid="7153361131709275746">"Wyłącz eSIM"</string> <string name="error_disable_esim_title" msgid="3802652622784813119">"Nie można wyłączyć karty eSIM"</string> <string name="error_disable_esim_msg" msgid="2441188596467999327">"Nie można wyłączyć karty eSIM z powodu błędu."</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index 5bfc3dbc900d..cc0c044c445a 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorreto."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string> diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index 5bfc3dbc900d..cc0c044c445a 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Digite sua senha"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Código PIN incorreto."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Carregado"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando sem fio"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string> diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 967255cb50e7..a141ed7ffaa6 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Vnesite geslo"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Napačna koda PIN."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neveljavna kartica"</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Baterija napolnjena"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Akumulator napolnjen"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brezžično polnjenje"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string> diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index 382a4dcafed7..1d34e3f8e099 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Fut fjalëkalimin"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"Kodi PIN është i pasaktë."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Karta e pavlefshme."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"I karikuar"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"I ngarkuar"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me valë"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string> diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index d44003bc5b95..74386bc7a487 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -134,7 +134,7 @@ <item quantity="other">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి. వివరాల కోసం కారియర్ను సంప్రదించండి.</item> <item quantity="one">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది వివరాల కోసం కారియర్ను సంప్రదించండి.</item> </plurals> - <string name="clock_title_default" msgid="6342735240617459864">"ఆటోమేటిక్"</string> + <string name="clock_title_default" msgid="6342735240617459864">"డిఫాల్ట్"</string> <string name="clock_title_bubble" msgid="2204559396790593213">"బబుల్"</string> <string name="clock_title_analog" msgid="8409262532900918273">"ఎనలాగ్"</string> </resources> diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index e157be4ac18e..aa9e693db0fa 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -135,6 +135,6 @@ <item quantity="one">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item> </plurals> <string name="clock_title_default" msgid="6342735240617459864">"ค่าเริ่มต้น"</string> - <string name="clock_title_bubble" msgid="2204559396790593213">"บับเบิล"</string> + <string name="clock_title_bubble" msgid="2204559396790593213">"ลูกโป่ง"</string> <string name="clock_title_analog" msgid="8409262532900918273">"แอนะล็อก"</string> </resources> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index 0fd5e17c953e..7b946aaf40da 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -71,7 +71,7 @@ <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"SIM PIN درج کریں۔"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" کیلئے SIM PIN درج کریں۔"</string> <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> موبائل سروس کے بغیر آلہ کا استعمال کرنے کیلئے eSIM غیر فعال کریں۔"</string> - <string name="kg_pin_instructions" msgid="822353548385014361">"PIN درج کریں"</string> + <string name="kg_pin_instructions" msgid="822353548385014361">"PIN درج کریں"</string> <string name="kg_password_instructions" msgid="324455062831719903">"پاسورڈ درج کریں"</string> <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM اب غیر فعال ہوگیا ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string> <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string> diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index 323fea5a608e..a6c2aa055c0b 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -33,7 +33,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Parolni kiriting"</string> <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"PIN kodi xato."</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM karta yaroqsiz."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Quvvat oldi"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Batareya quvvati to‘ldi"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz quvvatlanyapti"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvat olmoqda"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tezkor quvvat olmoqda"</string> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index 2ba5089c7ed9..31737fca5e4d 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -60,7 +60,7 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Không thể tắt eSIM do lỗi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Nhập"</string> <string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"Đã quên hình mở khóa"</string> - <string name="kg_wrong_pattern" msgid="5907301342430102842">"Hình mở khóa không chính xác"</string> + <string name="kg_wrong_pattern" msgid="5907301342430102842">"Hình không chính xác"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Mật khẩu sai"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Mã PIN sai"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914"> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index f7e9fedd5f66..4b6621379b44 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -79,6 +79,9 @@ is not fully charged, and it's plugged into a slow charger, say that it's charging slowly. --> <string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string> + <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that it's optimizing for battery health. --> + <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Optimizing for battery health</string> + <!-- When the lock screen is showing and the battery is low, warn user to plug in the phone soon. --> <string name="keyguard_low_battery">Connect your charger.</string> diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml index 170b32b6c669..d0ef10b649bf 100644 --- a/packages/SystemUI/res/layout/controls_dialog_pin.xml +++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml @@ -27,6 +27,7 @@ android:layout_height="wrap_content" android:minHeight="48dp" android:longClickable="false" + android:textAlignment="viewStart" android:inputType="numberPassword" /> <CheckBox android:id="@+id/controls_pin_use_alpha" diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml index e22a1660db0c..3a80561e702f 100644 --- a/packages/SystemUI/res/values-fi/strings_tv.xml +++ b/packages/SystemUI/res/values-fi/strings_tv.xml @@ -24,5 +24,5 @@ <string name="pip_close" msgid="5775212044472849930">"Sulje PIP"</string> <string name="pip_fullscreen" msgid="3877997489869475181">"Koko näyttö"</string> <string name="mic_active" msgid="5766614241012047024">"Mikrofoni aktiivinen"</string> - <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s sai pääsyn mikrofoniisi"</string> + <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s käytti mikrofoniasi"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml index 9b466788d9e0..22580e645ca0 100644 --- a/packages/SystemUI/res/values-nb/strings_tv.xml +++ b/packages/SystemUI/res/values-nb/strings_tv.xml @@ -24,5 +24,5 @@ <string name="pip_close" msgid="5775212044472849930">"Lukk PIP"</string> <string name="pip_fullscreen" msgid="3877997489869475181">"Fullskjerm"</string> <string name="mic_active" msgid="5766614241012047024">"Mikrofonen er aktiv"</string> - <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fikk tilgang til mikrofonen din"</string> + <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s brukte mikrofonen din"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml index 852ea5056460..5921aa7a9963 100644 --- a/packages/SystemUI/res/values-pl/strings_tv.xml +++ b/packages/SystemUI/res/values-pl/strings_tv.xml @@ -24,5 +24,5 @@ <string name="pip_close" msgid="5775212044472849930">"Zamknij PIP"</string> <string name="pip_fullscreen" msgid="3877997489869475181">"Pełny ekran"</string> <string name="mic_active" msgid="5766614241012047024">"Mikrofon aktywny"</string> - <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s uzyskała dostęp do mikrofonu"</string> + <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s korzystała z mikrofonu"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml index cf40057a005a..64d61621b001 100644 --- a/packages/SystemUI/res/values-sv/strings_tv.xml +++ b/packages/SystemUI/res/values-sv/strings_tv.xml @@ -24,5 +24,5 @@ <string name="pip_close" msgid="5775212044472849930">"Stäng PIP"</string> <string name="pip_fullscreen" msgid="3877997489869475181">"Helskärm"</string> <string name="mic_active" msgid="5766614241012047024">"Mikrofonen är aktiv"</string> - <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har fått åtkomst till mikrofonen"</string> + <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har använt mikrofonen"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml index 1cd63144b904..3cf2b43ed1ff 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml @@ -24,5 +24,5 @@ <string name="pip_close" msgid="5775212044472849930">"關閉 PIP"</string> <string name="pip_fullscreen" msgid="3877997489869475181">"全螢幕"</string> <string name="mic_active" msgid="5766614241012047024">"麥克風已啟用"</string> - <string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取您的麥克風"</string> + <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s 曾存取您的麥克風"</string> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 77ce39fe9953..95de4860ddfa 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2820,6 +2820,8 @@ <string name="controls_media_title">Media</string> <!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] --> <string name="controls_media_close_session">Hide the current session.</string> + <!-- Explanation that controls associated with a specific media session are active [CHAR_LIMIT=NONE] --> + <string name="controls_media_active_session">Current session cannot be hidden.</string> <!-- Label for a button that will hide media controls [CHAR_LIMIT=30] --> <string name="controls_media_dismiss_button">Dismiss</string> <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..57e656827f1c 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,12 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +101,27 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 5674fdd3bb36..eebf70b7564c 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -18,6 +18,7 @@ package com.android.systemui; import android.annotation.NonNull; import android.content.Context; +import android.content.res.AssetManager; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; @@ -39,6 +40,7 @@ import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvide import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.phone.BackGestureTfClassifierProvider; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -182,4 +184,13 @@ public class SystemUIFactory { return mContext; } } + + /** + * Creates an instance of BackGestureTfClassifierProvider. + * This method is overridden in vendor specific implementation of Sys UI. + */ + public BackGestureTfClassifierProvider createBackGestureTfClassifierProvider( + AssetManager am, String modelName) { + return new BackGestureTfClassifierProvider(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index dbe5a77965be..c1233fe6b9da 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -96,7 +96,7 @@ public class AuthContainerView extends LinearLayout @VisibleForTesting final WakefulnessLifecycle mWakefulnessLifecycle; - private @ContainerState int mContainerState = STATE_UNKNOWN; + @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN; // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet. @Nullable @AuthDialogCallback.DismissedReason Integer mPendingCallbackReason; @@ -607,10 +607,11 @@ public class AuthContainerView extends LinearLayout mWindowManager.removeView(this); } - private void onDialogAnimatedIn() { + @VisibleForTesting + void onDialogAnimatedIn() { if (mContainerState == STATE_PENDING_DISMISS) { Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now"); - animateAway(false /* sendReason */, 0); + animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); return; } mContainerState = STATE_SHOWING; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 1e556a3ed402..58d5776543a9 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -301,7 +301,7 @@ public class BubbleExpandedView extends LinearLayout { mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */, true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/, - true /* disableSurfaceViewBackgroundLayer */); + true /* disableSurfaceViewBackgroundLayer */, true /* useTrustedDisplay */); // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index aa11df41a7b7..a3a937acec76 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -301,7 +301,7 @@ class ToggleRangeBehavior : Behavior { } fun findNearestStep(value: Float): Float { - var minDiff = 1000f + var minDiff = Float.MAX_VALUE var f = rangeTemplate.getMinValue() while (f <= rangeTemplate.getMaxValue()) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 810cecca517f..d853e3d4a57c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -359,7 +359,15 @@ public class MediaControlPanel { final MediaController controller = getController(); mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller)); + // Guts label + boolean isDismissible = data.isClearable(); + mViewHolder.getSettingsText().setText(isDismissible + ? R.string.controls_media_close_session + : R.string.controls_media_active_session); + // Dismiss + mViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA); + mViewHolder.getDismiss().setEnabled(isDismissible); mViewHolder.getDismiss().setOnClickListener(v -> { if (mKey != null) { closeGuts(); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 436d4510aa67..833d08808a0b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -610,7 +610,8 @@ class MediaDataManager( // Move to resume key (aka package name) if that key doesn't already exist. val resumeAction = getResumeMediaAction(removed.resumeAction!!) val updated = removed.copy(token = null, actions = listOf(resumeAction), - actionsToShowInCompact = listOf(0), active = false, resumption = true) + actionsToShowInCompact = listOf(0), active = false, resumption = true, + isClearable = true) val pkg = removed?.packageName val migrate = mediaEntries.put(pkg, updated) == null // Notify listeners of "new" controls when migrating or removed and update when not diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt index dcb7767a680a..63a361de4d87 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt @@ -46,7 +46,7 @@ class MediaTimeoutListener @Inject constructor( /** * Callback representing that a media object is now expired: * @param token Media session unique identifier - * @param pauseTimeuot True when expired for {@code PAUSED_MEDIA_TIMEOUT} + * @param pauseTimeout True when expired for {@code PAUSED_MEDIA_TIMEOUT} */ lateinit var timeoutCallback: (String, Boolean) -> Unit @@ -57,11 +57,10 @@ class MediaTimeoutListener @Inject constructor( // Having an old key means that we're migrating from/to resumption. We should update // the old listener to make sure that events will be dispatched to the new location. val migrating = oldKey != null && key != oldKey - var wasPlaying = false if (migrating) { val reusedListener = mediaListeners.remove(oldKey) if (reusedListener != null) { - wasPlaying = reusedListener.playing ?: false + val wasPlaying = reusedListener.playing ?: false if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption") reusedListener.mediaData = data reusedListener.key = key @@ -159,9 +158,8 @@ class MediaTimeoutListener @Inject constructor( Log.v(TAG, "Execute timeout for $key") } timedOut = true - if (dispatchEvents) { - timeoutCallback(key, timedOut) - } + // this event is async, so it's safe even when `dispatchEvents` is false + timeoutCallback(key, timedOut) }, PAUSED_MEDIA_TIMEOUT) } else { expireMediaTimeout(key, "playback started - $state, $key") diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt index 666a6038a8b6..16327bd9064a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -60,8 +60,10 @@ class PlayerViewHolder private constructor(itemView: View) { val action4 = itemView.requireViewById<ImageButton>(R.id.action4) // Settings screen + val settingsText = itemView.requireViewById<TextView>(R.id.remove_text) val cancel = itemView.requireViewById<View>(R.id.cancel) - val dismiss = itemView.requireViewById<View>(R.id.dismiss) + val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss) + val dismissLabel = dismiss.getChildAt(0) val settings = itemView.requireViewById<View>(R.id.settings) init { diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt index 9e326aaec3c1..c8244589ce44 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt @@ -91,9 +91,9 @@ class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: R } private var playbackState: PlaybackState? = null private var callback = object : MediaController.Callback() { - override fun onPlaybackStateChanged(state: PlaybackState) { + override fun onPlaybackStateChanged(state: PlaybackState?) { playbackState = state - if (PlaybackState.STATE_NONE.equals(playbackState)) { + if (playbackState == null || PlaybackState.STATE_NONE.equals(playbackState)) { clearController() } else { checkIfPollingNeeded() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 8cd82cc77530..38e1de3cada0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -40,6 +40,7 @@ import android.os.Trace; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; +import android.service.notification.NotificationListenerService; import android.util.ArraySet; import android.util.Log; import android.view.View; @@ -52,6 +53,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.media.MediaData; import com.android.systemui.media.MediaDataManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.StatusBarModule; @@ -250,6 +252,24 @@ public class NotificationMediaManager implements Dumpable { } }); + mMediaDataManager.addListener(new MediaDataManager.Listener() { + @Override + public void onMediaDataLoaded(@NonNull String key, + @Nullable String oldKey, @NonNull MediaData data) { + } + + @Override + public void onMediaDataRemoved(@NonNull String key) { + NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key); + if (entry != null) { + // TODO(b/160713608): "removing" this notification won't happen and + // won't send the 'deleteIntent' if the notification is ongoing. + mEntryManager.performRemoveNotification(entry.getSbn(), + NotificationListenerService.REASON_CANCEL); + } + } + }); + mShowCompactMediaSeekbar = "true".equals( DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED)); 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 d04389d6cbe8..9fd729f425c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -574,6 +574,7 @@ public class NotificationEntryManager implements NotificationEntry entry = mPendingNotifications.get(key); if (entry != null) { entry.setSbn(notification); + entry.setRanking(ranking); } else { entry = new NotificationEntry( notification, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index e9cbf32ee052..943ace968632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -32,8 +32,6 @@ import javax.inject.Singleton; */ @Singleton public class RankingCoordinator implements Coordinator { - private static final String TAG = "RankingNotificationCoordinator"; - private final StatusBarStateController mStatusBarStateController; @Inject @@ -46,7 +44,7 @@ public class RankingCoordinator implements Coordinator { mStatusBarStateController.addCallback(mStatusBarStateCallback); pipeline.addPreGroupFilter(mSuspendedFilter); - pipeline.addPreGroupFilter(mDozingFilter); + pipeline.addPreGroupFilter(mDndVisualEffectsFilter); } /** @@ -61,10 +59,10 @@ public class RankingCoordinator implements Coordinator { } }; - private final NotifFilter mDozingFilter = new NotifFilter("IsDozingFilter") { + private final NotifFilter mDndVisualEffectsFilter = new NotifFilter( + "DndSuppressingVisualEffects") { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - // Dozing + DND Settings from Ranking object if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { return true; } @@ -77,7 +75,7 @@ public class RankingCoordinator implements Coordinator { new StatusBarStateController.StateListener() { @Override public void onDozingChanged(boolean isDozing) { - mDozingFilter.invalidateList(); + mDndVisualEffectsFilter.invalidateList(); } }; } 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 94e12e82f850..70dd80e71e7a 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 @@ -504,7 +504,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif - * or is in a whitelist). + * or is in an allowList). */ public boolean getIsNonblockable() { boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackGestureTfClassifierProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackGestureTfClassifierProvider.java new file mode 100644 index 000000000000..0af79c3886b9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BackGestureTfClassifierProvider.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 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.res.AssetManager; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class can be overridden by a vendor-specific sys UI implementation, + * in order to provide classification models for the Back Gesture. + */ +public class BackGestureTfClassifierProvider { + private static final String TAG = "BackGestureTfClassifierProvider"; + + /** + * Default implementation that returns an empty map. + * This method is overridden in vendor-specific Sys UI implementation. + * + * @param am An AssetManager to get the vocab file. + */ + public Map<String, Integer> loadVocab(AssetManager am) { + return new HashMap<String, Integer>(); + } + + /** + * This method is overridden in vendor-specific Sys UI implementation. + * + * @param featuresVector List of input features. + * + */ + public float predict(Object[] featuresVector) { + return -1; + } + + /** + * Interpreter owns resources. This method releases the resources after + * use to avoid memory leak. + * This method is overridden in vendor-specific Sys UI implementation. + * + */ + public void release() {} + + /** + * Returns whether to use the ML model for Back Gesture. + * This method is overridden in vendor-specific Sys UI implementation. + * + */ + public boolean isActive() { + return false; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 00a932cb1e8a..dc42997be0d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -56,6 +56,7 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.model.SysUiState; @@ -76,6 +77,7 @@ import com.android.systemui.tracing.nano.SystemUiTraceProto; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; /** @@ -117,8 +119,33 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa public void onTaskStackChanged() { mGestureBlockingActivityRunning = isGestureBlockingActivityRunning(); } + @Override + public void onTaskCreated(int taskId, ComponentName componentName) { + if (componentName != null) { + mPackageName = componentName.getPackageName(); + } else { + mPackageName = "_UNKNOWN"; + } + } }; + private DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace()) + && (properties.getKeyset().contains( + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_THRESHOLD) + || properties.getKeyset().contains( + SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL) + || properties.getKeyset().contains( + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_NAME))) { + updateMLModelState(); + } + } + }; + + private final Context mContext; private final OverviewProxyService mOverviewProxyService; private final Runnable mStateChangeCallback; @@ -173,6 +200,14 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa private int mRightInset; private int mSysUiFlags; + // For Tf-Lite model. + private BackGestureTfClassifierProvider mBackGestureTfClassifierProvider; + private Map<String, Integer> mVocab; + private boolean mUseMLModel; + private float mMLModelThreshold; + private String mPackageName; + private float mMLResults; + private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; private final NavigationEdgeBackPlugin.BackCallback mBackCallback = @@ -230,7 +265,6 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa Log.e(TAG, "Failed to add gesture blocking activities", e); } } - mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT, ViewConfiguration.getLongPressTimeout()); @@ -344,6 +378,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this); mPluginManager.removePluginListener(this); ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener); + DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); try { WindowManagerGlobal.getWindowManagerService() @@ -359,6 +394,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, mContext.getMainThreadHandler()); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, + runnable -> (mContext.getMainThreadHandler()).post(runnable), + mOnPropertiesChangedListener); try { WindowManagerGlobal.getWindowManagerService() @@ -379,6 +417,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa mPluginManager.addPluginListener( this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false); } + // Update the ML model resources. + updateMLModelState(); } @Override @@ -431,12 +471,72 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa } } + private void updateMLModelState() { + boolean newState = mIsEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false); + + if (newState == mUseMLModel) { + return; + } + + if (newState) { + String mlModelName = DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_NAME, "backgesture"); + mBackGestureTfClassifierProvider = SystemUIFactory.getInstance() + .createBackGestureTfClassifierProvider(mContext.getAssets(), mlModelName); + mMLModelThreshold = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_THRESHOLD, 0.9f); + if (mBackGestureTfClassifierProvider.isActive()) { + mVocab = mBackGestureTfClassifierProvider.loadVocab(mContext.getAssets()); + mUseMLModel = true; + return; + } + } + + mUseMLModel = false; + if (mBackGestureTfClassifierProvider != null) { + mBackGestureTfClassifierProvider.release(); + mBackGestureTfClassifierProvider = null; + } + } + + private float getBackGesturePredictionsCategory(int x, int y) { + if (!mVocab.containsKey(mPackageName)) { + return -1; + } + + int distanceFromEdge; + int location; + if (x <= mDisplaySize.x / 2.0) { + location = 1; // left + distanceFromEdge = x; + } else { + location = 2; // right + distanceFromEdge = mDisplaySize.x - x; + } + + Object[] featuresVector = { + new long[]{(long) mDisplaySize.x}, + new long[]{(long) distanceFromEdge}, + new long[]{(long) location}, + new long[]{(long) mVocab.get(mPackageName)}, + new long[]{(long) y}, + }; + + mMLResults = mBackGestureTfClassifierProvider.predict(featuresVector); + if (mMLResults == -1) return -1; + + return mMLResults >= mMLModelThreshold ? 1 : 0; + } + private boolean isWithinTouchRegion(int x, int y) { + boolean withinRange = false; + float results = -1; + // Disallow if we are in the bottom gesture area if (y >= (mDisplaySize.y - mBottomGestureHeight)) { return false; } - // If the point is way too far (twice the margin), it is // not interesting to us for logging purposes, nor we // should process it. Simply return false and keep @@ -446,11 +546,15 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa return false; } - // Denotes whether we should proceed with the gesture. - // Even if it is false, we may want to log it assuming - // it is not invalid due to exclusion. - boolean withinRange = x <= mEdgeWidthLeft + mLeftInset - || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); + if (mUseMLModel && (results = getBackGesturePredictionsCategory(x, y)) != -1) { + withinRange = results == 1 ? true : false; + } else { + // Denotes whether we should proceed with the gesture. + // Even if it is false, we may want to log it assuming + // it is not invalid due to exclusion. + withinRange = x <= mEdgeWidthLeft + mLeftInset + || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); + } // Always allow if the user is in a transient sticky immersive state if (mIsNavBarShownTransiently) { @@ -493,6 +597,11 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa return; } mLogGesture = false; + String logPackageName = ""; + // Due to privacy, only top 100 most used apps by all users can be logged. + if (mUseMLModel && mVocab.containsKey(mPackageName) && mVocab.get(mPackageName) < 100) { + logPackageName = mPackageName; + } SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backType, (int) mDownPoint.y, mIsOnLeftEdge ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT @@ -500,7 +609,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa (int) mDownPoint.x, (int) mDownPoint.y, (int) mEndPoint.x, (int) mEndPoint.y, mEdgeWidthLeft + mLeftInset, - mDisplaySize.x - (mEdgeWidthRight + mRightInset)); + mDisplaySize.x - (mEdgeWidthRight + mRightInset), + mUseMLModel ? mMLResults : -2, logPackageName); } private void onMotionEvent(MotionEvent ev) { @@ -509,6 +619,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa // Verify if this is in within the touch region and we aren't in immersive mode, and // either the bouncer is showing or the notification panel is hidden mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset; + mMLResults = 0; mLogGesture = false; mInRejectedExclusion = false; mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed @@ -648,6 +759,11 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa ActivityManager.RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); ComponentName topActivity = runningTask == null ? null : runningTask.topActivity; + if (topActivity != null) { + mPackageName = topActivity.getPackageName(); + } else { + mPackageName = "_UNKNOWN"; + } return topActivity != null && mGestureBlockingActivities.contains(topActivity); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java index 286b7c049fc7..21d700e41a40 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java @@ -35,6 +35,8 @@ import android.os.UserHandle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; @@ -58,6 +60,9 @@ public class UsbConfirmActivity extends AlertActivity @Override public void onCreate(Bundle icicle) { + getWindow().addSystemFlags( + WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + super.onCreate(icicle); Intent intent = getIntent(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java index 29d7a524dd8b..5f3f3a79e31d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java @@ -204,6 +204,16 @@ public class AuthContainerViewTest extends SysuiTestCase { } @Test + public void testOnDialogAnimatedIn_sendsCancelReason_whenPendingDismiss() { + initializeContainer(Authenticators.BIOMETRIC_WEAK); + mAuthContainer.mContainerState = AuthContainerView.STATE_PENDING_DISMISS; + mAuthContainer.onDialogAnimatedIn(); + verify(mCallback).onDismissed( + eq(AuthDialogCallback.DISMISSED_USER_CANCELED), + eq(null) /* credentialAttestation */); + } + + @Test public void testLayoutParams_hasSecureWindowFlag() { final IBinder windowToken = mock(IBinder.class); final WindowManager.LayoutParams layoutParams = diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt new file mode 100644 index 000000000000..31e09549a2b5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 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.controls.ui + +import android.service.controls.templates.RangeTemplate +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ToggleRangeTemplateTest : SysuiTestCase() { + + @Test + fun testLargeRangeNearestStep() { + val trt = ToggleRangeBehavior() + trt.rangeTemplate = RangeTemplate("range", -100000f, 100000f, 0f, 5f, null) + + assertEquals(255f, trt.findNearestStep(253f), 0.1f) + } + + @Test + fun testLargeRangeNearestStepWithNegativeValues() { + val trt = ToggleRangeBehavior() + trt.rangeTemplate = RangeTemplate("range", -100000f, 100000f, 0f, 5f, null) + + assertEquals(-7855f, trt.findNearestStep(-7853.2f), 0.1f) + } + + @Test + fun testFractionalRangeNearestStep() { + val trt = ToggleRangeBehavior() + trt.rangeTemplate = RangeTemplate("range", 10f, 11f, 10f, .01f, null) + + assertEquals(10.54f, trt.findNearestStep(10.543f), 0.01f) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 81139f192070..ad703614fdb4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -109,9 +109,11 @@ public class MediaControlPanelTest : SysuiTestCase() { private lateinit var action2: ImageButton private lateinit var action3: ImageButton private lateinit var action4: ImageButton + private lateinit var settingsText: TextView private lateinit var settings: View private lateinit var cancel: View - private lateinit var dismiss: View + private lateinit var dismiss: FrameLayout + private lateinit var dismissLabel: View private lateinit var session: MediaSession private val device = MediaDeviceData(true, null, DEVICE_NAME) @@ -168,12 +170,16 @@ public class MediaControlPanelTest : SysuiTestCase() { whenever(holder.action3).thenReturn(action3) action4 = ImageButton(context) whenever(holder.action4).thenReturn(action4) + settingsText = TextView(context) + whenever(holder.settingsText).thenReturn(settingsText) settings = View(context) whenever(holder.settings).thenReturn(settings) cancel = View(context) whenever(holder.cancel).thenReturn(cancel) - dismiss = View(context) + dismiss = FrameLayout(context) whenever(holder.dismiss).thenReturn(dismiss) + dismissLabel = View(context) + whenever(holder.dismissLabel).thenReturn(dismissLabel) // Create media session val metadataBuilder = MediaMetadata.Builder().apply { @@ -327,6 +333,7 @@ public class MediaControlPanelTest : SysuiTestCase() { notificationKey = KEY) player.bind(state, mediaKey) + assertThat(dismiss.isEnabled).isEqualTo(true) dismiss.callOnClick() val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java) verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean()) @@ -334,4 +341,16 @@ public class MediaControlPanelTest : SysuiTestCase() { captor.value.onDismiss() verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong()) } + + @Test + fun dismissButtonDisabled() { + val mediaKey = "key for dismissal" + player.attach(holder) + val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), + emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null, + isClearable = false, notificationKey = KEY) + player.bind(state, mediaKey) + + assertThat(dismiss.isEnabled).isEqualTo(false) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt index b81ab74458ce..1f9862c07a4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt @@ -654,4 +654,21 @@ public class SeekBarViewModelTest : SysuiTestCase() { fakeExecutor.runAllReady() verify(mockController).unregisterCallback(any()) } + + @Test + fun nullPlaybackStateUnregistersCallback() { + viewModel.updateController(mockController) + val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java) + verify(mockController).registerCallback(captor.capture()) + val callback = captor.value + // WHEN the callback receives a null state + callback.onPlaybackStateChanged(null) + with(fakeExecutor) { + advanceClockToNext() + runAllReady() + } + // THEN we unregister callback (as a result of clearing the controller) + fakeExecutor.runAllReady() + verify(mockController).unregisterCallback(any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 90423c18216a..f1e6bf604a14 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -382,6 +382,36 @@ public class NotificationEntryManagerTest extends SysuiTestCase { } @Test + public void testUpdatePendingNotification_rankingUpdated() { + // GIVEN a notification with ranking is pending + final Ranking originalRanking = mEntry.getRanking(); + mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry); + + // WHEN the same notification has been updated with a new ranking + final int newRank = 2345; + doAnswer(invocationOnMock -> { + Ranking ranking = (Ranking) + invocationOnMock.getArguments()[1]; + ranking.populate( + mEntry.getKey(), + newRank, /* this changed!! */ + false, + 0, + 0, + IMPORTANCE_DEFAULT, + null, null, + null, null, null, true, + Ranking.USER_SENTIMENT_NEUTRAL, false, -1, + false, null, null, false, false, false, null, false); + return true; + }).when(mRankingMap).getRanking(eq(mEntry.getKey()), any(Ranking.class)); + mEntryManager.addNotification(mSbn, mRankingMap); + + // THEN ranking for the entry has been updated with new ranking + assertEquals(newRank, mEntry.getRanking().getRank()); + } + + @Test public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() { // GIVEN an entry manager with a notification mEntryManager.addActiveNotificationForTest(mEntry); diff --git a/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_bluetooth_transient_animation.xml b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_bluetooth_transient_animation.xml new file mode 100644 index 000000000000..035455df11bb --- /dev/null +++ b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_bluetooth_transient_animation.xml @@ -0,0 +1,219 @@ +<!-- +/** + * Copyright (C) 2020, 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. + */ +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group android:name="_R_G"> + <group android:name="_R_G_L_0_G"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData=" M6.5 12 C6.5,11.17 5.83,10.5 5,10.5 C4.17,10.5 3.5,11.17 3.5,12 C3.5,12.83 4.17,13.5 5,13.5 C5.83,13.5 6.5,12.83 6.5,12c " /> + <path + android:name="_R_G_L_0_G_D_1_P_0" + android:fillAlpha="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData=" M19 10.5 C18.17,10.5 17.5,11.17 17.5,12 C17.5,12.83 18.17,13.5 19,13.5 C19.83,13.5 20.5,12.83 20.5,12 C20.5,11.17 19.83,10.5 19,10.5c " /> + <path + android:name="_R_G_L_0_G_D_2_P_0" + android:pathData=" M6.49 5.98 C6.49,5.98 17.25,16.74 17.25,16.74 C17.25,16.74 17.25,17.28 17.25,17.28 C17.25,17.28 13.3,21.23 13.3,21.23 C13.3,21.23 12.5,21.23 12.5,21.23 C12.5,21.23 12.5,2.75 12.5,2.75 C12.5,2.75 13.3,2.75 13.3,2.75 C13.3,2.75 17.25,6.7 17.25,6.7 C17.25,6.7 17.25,7.24 17.25,7.24 C17.25,7.24 6.49,18 6.49,18 " + android:strokeWidth="1.5" + android:strokeAlpha="1" + android:strokeColor="#000000" /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="233" + android:propertyName="fillAlpha" + android:startOffset="17" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="250" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="233" + android:propertyName="fillAlpha" + android:startOffset="267" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="500" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="233" + android:propertyName="fillAlpha" + android:startOffset="517" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="750" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="250" + android:propertyName="fillAlpha" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="250" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="233" + android:propertyName="fillAlpha" + android:startOffset="267" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="500" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="233" + android:propertyName="fillAlpha" + android:startOffset="517" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="750" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="1017" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_hotspot_transient_animation.xml b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_hotspot_transient_animation.xml new file mode 100644 index 000000000000..235e67f31974 --- /dev/null +++ b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_hotspot_transient_animation.xml @@ -0,0 +1,204 @@ +<!-- +/** + * Copyright (C) 2020, 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. + */ +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group android:name="_R_G"> + <group android:name="_R_G_L_0_G"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#000000" + android:fillType="nonZero" + android:pathData=" M12 11 C10.9,11 10,11.9 10,13 C10,14.1 10.9,15 12,15 C13.1,15 14,14.1 14,13 C14,11.9 13.1,11 12,11c " /> + <path + android:name="_R_G_L_0_G_D_1_P_0" + android:pathData=" M8.29 16.71 C7.34,15.76 6.75,14.45 6.75,13 C6.75,10.1 9.1,7.75 12,7.75 C14.9,7.75 17.25,10.1 17.25,13 C17.25,14.45 16.66,15.76 15.71,16.71 " + android:strokeWidth="1.5" + android:strokeAlpha="1" + android:strokeColor="#000000" + /> + <path + android:name="_R_G_L_0_G_D_2_P_0" + android:pathData=" M5.46 19.54 C3.79,17.87 2.75,15.56 2.75,13 C2.75,7.89 6.89,3.75 12,3.75 C17.11,3.75 21.25,7.89 21.25,13 C21.25,15.56 20.21,17.87 18.54,19.54 " + android:strokeWidth="1.5" + android:strokeAlpha="1" + android:strokeColor="#000000" /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="583" + android:propertyName="fillAlpha" + android:startOffset="17" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="600" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="200" + android:propertyName="strokeAlpha" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="strokeAlpha" + android:startOffset="200" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="583" + android:propertyName="strokeAlpha" + android:startOffset="217" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="strokeAlpha" + android:startOffset="800" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_2_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="400" + android:propertyName="strokeAlpha" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="strokeAlpha" + android:startOffset="400" + android:valueFrom="1" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="583" + android:propertyName="strokeAlpha" + android:startOffset="417" + android:valueFrom="0.5" + android:valueTo="0.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="strokeAlpha" + android:startOffset="1000" + android:valueFrom="0.5" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="1250" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_signal_wifi_transient_animation.xml b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_signal_wifi_transient_animation.xml new file mode 100644 index 000000000000..b988fdf67191 --- /dev/null +++ b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_signal_wifi_transient_animation.xml @@ -0,0 +1,18 @@ +<!-- +/** + * Copyright (C) 2020, 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. + */ +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="24dp" android:width="24dp" android:viewportHeight="24" android:viewportWidth="24"><group android:name="_R_G"><group android:name="_R_G_L_1_G"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M12 2 C7.76,2 3.89,3.67 1,6.38 C1,6.38 1,8.61 1,8.61 C1,8.61 11,21 11,21 C11,21 13,21 13,21 C13,21 23,8.61 23,8.61 C23,8.61 23,6.38 23,6.38 C20.11,3.67 16.24,2 12,2c M12 19.85 C12,19.85 2.02,7.49 2.02,7.49 C4.78,4.91 8.28,3.5 12,3.5 C15.73,3.5 19.23,4.91 21.98,7.49 C21.98,7.49 12,19.85 12,19.85c "/><path android:name="_R_G_L_1_G_D_1_P_0" android:fillColor="#000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M12 13 C9.9,13 7.9,13.9 6.6,15.4 C6.6,15.4 12,21 12,21 C12,21 17.4,15.4 17.4,15.4 C16.1,13.9 14.1,13 12,13c "/><path android:name="_R_G_L_1_G_D_2_P_0" android:fillColor="#000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M12 10 C9.2,10 6.5,11.2 4.8,13.2 C4.8,13.2 12,21 12,21 C12,21 19.2,13.2 19.2,13.2 C17.5,11.2 14.8,10 12,10c "/><path android:name="_R_G_L_1_G_D_3_P_0" android:fillColor="#000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M12 7 C8.5,7 5.2,8.5 3,11 C3,11 12,21 12,21 C12,21 21,11 21,11 C18.8,8.5 15.5,7 12,7c "/><path android:name="_R_G_L_1_G_D_4_P_0" android:fillColor="#000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M12 2 C7.76,2 3.89,3.67 1,6.38 C1,6.38 1,8.61 1,8.61 C1,8.61 11,21 11,21 C11,21 13,21 13,21 C13,21 23,8.61 23,8.61 C23,8.61 23,6.38 23,6.38 C20.11,3.67 16.24,2 12,2c "/></group><group android:name="_R_G_L_0_G"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M12 2 C7.76,2 3.89,3.67 1,6.38 C1,6.38 1,8.61 1,8.61 C1,8.61 11,21 11,21 C11,21 13,21 13,21 C13,21 23,8.61 23,8.61 C23,8.61 23,6.38 23,6.38 C20.11,3.67 16.24,2 12,2c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="150" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="17" android:startOffset="150" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_2_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="317" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="17" android:startOffset="317" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_3_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="483" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="17" android:startOffset="483" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="667" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="650" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="17" android:startOffset="650" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="0" android:startOffset="600" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="850" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file diff --git a/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_work_apps_off.xml b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_work_apps_off.xml new file mode 100644 index 000000000000..22540e2dee15 --- /dev/null +++ b/packages/overlays/IconPackVictorAndroidOverlay/res/drawable/ic_work_apps_off.xml @@ -0,0 +1,19 @@ +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector android:height="32dp" android:viewportHeight="24" android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19.5,19.5l-6-6L12,12L7.5,7.5L6,6L2.81,2.81L1.75,3.87L3.88,6H3.41L2,7.41v12.17L3.41,21h15.46l1.25,1.25l1.06-1.06 l-0.4-0.4L19.5,19.5z M3.5,19.5v-12h1.88l5.3,5.3c-0.11,0.21-0.18,0.44-0.18,0.7c0,0.83,0.67,1.5,1.5,1.5 c0.25,0,0.49-0.07,0.7-0.18l4.68,4.68H3.5z"/> + <path android:fillColor="@android:color/white" android:pathData="M9.62,7.5H20.5v10.88l1.35,1.35L22,19.59V7.41L20.59,6H16V3.41L14.59,2H9.41L8,3.41v2.46L9.62,7.5z M9.5,3.5h5V6h-5V3.5z"/> +</vector>
\ No newline at end of file diff --git a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml index 2465fe015538..e7eeb30501b5 100644 --- a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml +++ b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml @@ -18,7 +18,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. --> - <string name="config_icon_mask" translatable="false">"MM55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z"</string> + <string name="config_icon_mask" translatable="false">"M55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z"</string> <!-- Flag indicating whether round icons should be parsed from the application manifest. --> <bool name="config_useRoundIcon">false</bool> <!-- Corner radius of system dialogs --> diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 40a2816ee7de..8822d55cc30f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -148,6 +148,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; + boolean mRequestFilterKeyEvents; boolean mRetrieveInteractiveWindows; @@ -323,8 +325,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0; mRequestMultiFingerGestures = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0; - mRequestFilterKeyEvents = (info.flags - & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; + mRequestTwoFingerPassthrough = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0; + mRequestFilterKeyEvents = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; mRetrieveInteractiveWindows = (info.flags & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; mCaptureFingerprintGestures = (info.flags @@ -1773,6 +1777,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return mRequestMultiFingerGestures; } + public boolean isTwoFingerPassthroughEnabled() { + return mRequestTwoFingerPassthrough; + } + @Override public void setGestureDetectionPassthroughRegion(int displayId, Region region) { mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 020f2253743d..a04a7c570b5c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -114,6 +114,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100; + /** + * Flag for enabling multi-finger gestures. + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x00000200; + static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS | FLAG_FEATURE_AUTOCLICK @@ -121,7 +128,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER | FLAG_SERVICE_HANDLES_DOUBLE_TAP - | FLAG_REQUEST_MULTI_FINGER_GESTURES; + | FLAG_REQUEST_MULTI_FINGER_GESTURES + | FLAG_REQUEST_2_FINGER_PASSTHROUGH; private final Context mContext; @@ -417,6 +425,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { explorer.setMultiFingerGesturesEnabled(true); } + if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) { + explorer.setTwoFingerPassthroughEnabled(true); + } addFirstEventHandler(displayId, explorer); mTouchExplorer.put(displayId, explorer); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index fcf270b4ef35..9c10bad1775a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1742,6 +1742,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isMultiFingerGesturesEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; } + if (userState.isTwoFingerPassthroughEnabledLocked()) { + flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH; + } } if (userState.isFilterKeyEventsEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; @@ -2020,6 +2023,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); boolean serviceHandlesDoubleTapEnabled = false; boolean requestMultiFingerGestures = false; + boolean requestTwoFingerPassthrough = false; final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); @@ -2027,6 +2031,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub touchExplorationEnabled = true; serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); + requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled(); break; } } @@ -2043,6 +2048,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); + userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); } private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 0845d019c060..299a776df1d0 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -109,6 +109,7 @@ class AccessibilityUserState { private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; private int mUserInteractiveUiTimeout; private int mUserNonInteractiveUiTimeout; private int mNonInteractiveUiTimeout = 0; @@ -160,6 +161,7 @@ class AccessibilityUserState { mIsTouchExplorationEnabled = false; mServiceHandlesDoubleTap = false; mRequestMultiFingerGestures = false; + mRequestTwoFingerPassthrough = false; mIsDisplayMagnificationEnabled = false; mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; @@ -446,6 +448,8 @@ class AccessibilityUserState { .append(String.valueOf(mServiceHandlesDoubleTap)); pw.append(", requestMultiFingerGestures=") .append(String.valueOf(mRequestMultiFingerGestures)); + pw.append(", requestTwoFingerPassthrough=") + .append(String.valueOf(mRequestTwoFingerPassthrough)); pw.append(", displayMagnificationEnabled=").append(String.valueOf( mIsDisplayMagnificationEnabled)); pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled)); @@ -733,6 +737,14 @@ class AccessibilityUserState { public void setMultiFingerGesturesLocked(boolean enabled) { mRequestMultiFingerGestures = enabled; } + public boolean isTwoFingerPassthroughEnabledLocked() { + return mRequestTwoFingerPassthrough; + } + + public void setTwoFingerPassthroughLocked(boolean enabled) { + mRequestTwoFingerPassthrough = enabled; + } + public int getUserInteractiveUiTimeoutLocked() { return mUserInteractiveUiTimeout; diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index 070626be9f80..a4fec82bcf56 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -256,6 +256,7 @@ class EventDispatcher { return actionMasked; } } + /** * Sends down events to the view hierarchy for all pointers which are not already being * delivered i.e. pointers that are not yet injected. @@ -285,6 +286,79 @@ class EventDispatcher { } /** + * Sends down events to the view hierarchy for all pointers which are not already being + * delivered with original down location. i.e. pointers that are not yet injected. The down time + * is also replaced by the original one. + * + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + void sendDownForAllNotInjectedPointersWithOriginalDown(MotionEvent prototype, int policyFlags) { + // Inject the injected pointers. + int pointerIdBits = 0; + final int pointerCount = prototype.getPointerCount(); + final MotionEvent event = computeEventWithOriginalDown(prototype); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = prototype.getPointerId(i); + // Do not send event for already delivered pointers. + if (!mState.isInjectedPointerDown(pointerId)) { + pointerIdBits |= (1 << pointerId); + final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); + sendMotionEvent( + event, + action, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); + } + } + } + + private MotionEvent computeEventWithOriginalDown(MotionEvent prototype) { + final int pointerCount = prototype.getPointerCount(); + if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) { + Slog.w(LOG_TAG, "The pointer count doesn't match the received count."); + return MotionEvent.obtain(prototype); + } + MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount]; + MotionEvent.PointerProperties[] properties = + new MotionEvent.PointerProperties[pointerCount]; + for (int i = 0; i < pointerCount; ++i) { + final int pointerId = prototype.getPointerId(i); + final float x = mState.getReceivedPointerTracker().getReceivedPointerDownX(pointerId); + final float y = mState.getReceivedPointerTracker().getReceivedPointerDownY(pointerId); + coords[i] = new MotionEvent.PointerCoords(); + coords[i].x = x; + coords[i].y = y; + properties[i] = new MotionEvent.PointerProperties(); + properties[i].id = pointerId; + properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER; + } + MotionEvent event = + MotionEvent.obtain( + prototype.getDownTime(), + // The event time is used for downTime while sending ACTION_DOWN. We adjust + // it to avoid the motion velocity is too fast in the beginning after + // Delegating. + prototype.getDownTime(), + prototype.getAction(), + pointerCount, + properties, + coords, + prototype.getMetaState(), + prototype.getButtonState(), + prototype.getXPrecision(), + prototype.getYPrecision(), + prototype.getDeviceId(), + prototype.getEdgeFlags(), + prototype.getSource(), + prototype.getFlags()); + return event; + } + + /** + * * Sends up events to the view hierarchy for all pointers which are already being delivered i.e. * pointers that are injected. * diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java index 5c15214284f0..7f07c2878088 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -94,17 +94,23 @@ class GestureManifold implements GestureMatcher.StateChangeListener { private boolean mServiceHandlesDoubleTap = false; // Whether multi-finger gestures are enabled. boolean mMultiFingerGesturesEnabled; + // Whether the two-finger passthrough is enabled when multi-finger gestures are enabled. + private boolean mTwoFingerPassthroughEnabled; // A list of all the multi-finger gestures, for easy adding and removal. private final List<GestureMatcher> mMultiFingerGestures = new ArrayList<>(); + // A list of two-finger swipes, for easy adding and removal when turning on or off two-finger + // passthrough. + private final List<GestureMatcher> mTwoFingerSwipes = new ArrayList<>(); // Shared state information. private TouchState mState; - GestureManifold(Context context, Listener listener, TouchState state) { + GestureManifold(Context context, Listener listener, TouchState state, Handler handler) { mContext = context; - mHandler = new Handler(context.getMainLooper()); + mHandler = handler; mListener = listener; mState = state; mMultiFingerGesturesEnabled = false; + mTwoFingerPassthroughEnabled = false; // Set up gestures. // Start with double tap. mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this)); @@ -161,14 +167,14 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mMultiFingerGestures.add( new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this)); // Two-finger swipes. - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, LEFT, GESTURE_2_FINGER_SWIPE_LEFT, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, RIGHT, GESTURE_2_FINGER_SWIPE_RIGHT, this)); - mMultiFingerGestures.add( - new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mTwoFingerSwipes.add(new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mMultiFingerGestures.addAll(mTwoFingerSwipes); // Three-finger swipes. mMultiFingerGestures.add( new MultiFingerSwipe(context, 3, DOWN, GESTURE_3_FINGER_SWIPE_DOWN, this)); @@ -360,6 +366,25 @@ class GestureManifold implements GestureMatcher.StateChangeListener { } } + public boolean isTwoFingerPassthroughEnabled() { + return mTwoFingerPassthroughEnabled; + } + + public void setTwoFingerPassthroughEnabled(boolean mode) { + if (mTwoFingerPassthroughEnabled != mode) { + mTwoFingerPassthroughEnabled = mode; + if (!mode) { + mMultiFingerGestures.addAll(mTwoFingerSwipes); + if (mMultiFingerGesturesEnabled) { + mGestures.addAll(mTwoFingerSwipes); + } + } else { + mMultiFingerGestures.removeAll(mTwoFingerSwipes); + mGestures.removeAll(mTwoFingerSwipes); + } + } + } + public void setServiceHandlesDoubleTap(boolean mode) { mServiceHandlesDoubleTap = mode; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java index 4b89731b75b6..2a305397924f 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java @@ -294,7 +294,7 @@ class MultiFingerSwipe extends GestureMatcher { + Float.toString(mGestureDetectionThresholdPixels)); } if (getState() == STATE_CLEAR) { - if (moveDelta < mTouchSlop) { + if (moveDelta < (mTargetFingerCount * mTouchSlop)) { // This still counts as a touch not a swipe. continue; } else if (mStrokeBuffers[pointerIndex].size() == 0) { diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 6074ac94faf3..b6126d741718 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -24,6 +24,7 @@ import android.accessibilityservice.AccessibilityGestureEvent; import android.content.Context; import android.graphics.Region; import android.os.Handler; +import android.util.DisplayMetrics; import android.util.Slog; import android.view.InputDevice; import android.view.MotionEvent; @@ -73,12 +74,21 @@ public class TouchExplorer extends BaseEventStreamTransformation // The timeout after which we are no longer trying to detect a gesture. private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000; + // The height of the top and bottom edges for edge-swipes. + // For now this is only used to allow three-finger edge-swipes from the bottom. + private static final float EDGE_SWIPE_HEIGHT_CM = 0.25f; + + // The calculated edge height for the top and bottom edges. + private final float mEdgeSwipeHeightPixels; // Timeout before trying to decide what the user is trying to do. private final int mDetermineUserIntentTimeout; // Slop between the first and second tap to be a double tap. private final int mDoubleTapSlop; + // Slop to move before being considered a move rather than a tap. + private final int mTouchSlop; + // The current state of the touch explorer. private TouchState mState; @@ -151,6 +161,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher = new EventDispatcher(context, mAms, super.getNext(), mState); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); + mEdgeSwipeHeightPixels = metrics.ydpi / GestureUtils.CM_PER_INCH * EDGE_SWIPE_HEIGHT_CM; mHandler = new Handler(context.getMainLooper()); mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed(); mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed(); @@ -162,7 +175,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityEvent.TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout); if (detector == null) { - mGestureDetector = new GestureManifold(context, this, mState); + mGestureDetector = new GestureManifold(context, this, mState, mHandler); } else { mGestureDetector = detector; } @@ -196,16 +209,10 @@ public class TouchExplorer extends BaseEventStreamTransformation if (mState.isTouchExploring()) { // If a touch exploration gesture is in progress send events for its end. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); - } else if (mState.isDragging()) { - mDraggingPointerId = INVALID_POINTER_ID; - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isDelegating()) { - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isGestureDetecting()) { - // No state specific cleanup required. } + mDraggingPointerId = INVALID_POINTER_ID; + // Send exit to any pointers that we have delivered as part of delegating or dragging. + mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); // Remove all pending callbacks. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); @@ -214,6 +221,8 @@ public class TouchExplorer extends BaseEventStreamTransformation mSendTouchInteractionEndDelayed.cancel(); // Clear the gesture detector mGestureDetector.clear(); + // Clear the offset data by long pressing. + mDispatcher.clear(); // Go to initial state. mState.clear(); mAms.onTouchInteractionEnd(); @@ -344,7 +353,6 @@ public class TouchExplorer extends BaseEventStreamTransformation public boolean onGestureStarted() { // We have to perform gesture detection, so // clear the current state and try to detect. - mState.startGestureDetecting(); mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); mExitGestureDetectionModeDelayed.post(); @@ -533,6 +541,7 @@ public class TouchExplorer extends BaseEventStreamTransformation sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } } + /** * Handles ACTION_MOVE while in the touch interacting state. This is where transitions to * delegating and dragging states are handled. @@ -541,7 +550,7 @@ public class TouchExplorer extends BaseEventStreamTransformation MotionEvent event, MotionEvent rawEvent, int policyFlags) { final int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); final int pointerIndex = event.findPointerIndex(pointerId); - final int pointerIdBits = (1 << pointerId); + int pointerIdBits = (1 << pointerId); switch (event.getPointerCount()) { case 1: // We have not started sending events since we try to @@ -552,12 +561,37 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } // Make sure we don't have any pending transitions to touch exploration mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); + if (mGestureDetector.isMultiFingerGesturesEnabled() + && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (pointerIndex < 0) { + return; + } + // Require both fingers to have moved a certain amount before starting a drag. + for (int index = 0; index < event.getPointerCount(); ++index) { + int id = event.getPointerId(index); + if (!mReceivedPointerTracker.isReceivedPointerDown(id)) { + // Something is wrong with the event stream. + Slog.e(LOG_TAG, "Invalid pointer id: " + id); + } + final float deltaX = + mReceivedPointerTracker.getReceivedPointerDownX(id) + - rawEvent.getX(index); + final float deltaY = + mReceivedPointerTracker.getReceivedPointerDownY(id) + - rawEvent.getY(index); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < (2 * mTouchSlop)) { + return; + } + } + } // More than one pointer so the user is not touch exploring // and now we have to decide whether to delegate or drag. // Remove move history before send injected non-move events @@ -565,12 +599,20 @@ public class TouchExplorer extends BaseEventStreamTransformation if (isDraggingGesture(event)) { // Two pointers moving in the same direction within // a given distance perform a drag. - mState.startDragging(); - mDraggingPointerId = pointerId; - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); + pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); - mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + MotionEvent downEvent = computeDownEventForDrag(event); + if (downEvent != null) { + mDispatcher.sendMotionEvent(downEvent, MotionEvent.ACTION_DOWN, rawEvent, + pointerIdBits, policyFlags); + mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_MOVE, rawEvent, + pointerIdBits, policyFlags); + } else { + mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_DOWN, rawEvent, + pointerIdBits, policyFlags); + } + mState.startDragging(); } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mState.startDelegating(); @@ -579,12 +621,31 @@ public class TouchExplorer extends BaseEventStreamTransformation break; default: if (mGestureDetector.isMultiFingerGesturesEnabled()) { - return; + if (mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (event.getPointerCount() == 3) { + // If three fingers went down on the bottom edge of the screen, delegate + // immediately. + if (allPointersDownOnBottomEdge(event)) { + if (DEBUG) { + Slog.d(LOG_TAG, "Three-finger edge swipe detected."); + } + mState.startDelegating(); + if (mState.isTouchExploring()) { + mDispatcher.sendDownForAllNotInjectedPointers(event, + policyFlags); + } else { + mDispatcher.sendDownForAllNotInjectedPointersWithOriginalDown( + event, policyFlags); + } + } + } + } + } else { + // More than two pointers are delegated to the view hierarchy. + mState.startDelegating(); + event = MotionEvent.obtainNoHistory(event); + mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); } - // More than two pointers are delegated to the view hierarchy. - mState.startDelegating(); - event = MotionEvent.obtainNoHistory(event); - mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); break; } } @@ -626,7 +687,8 @@ public class TouchExplorer extends BaseEventStreamTransformation event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } if (mSendHoverEnterAndMoveDelayed.isPending()) { @@ -681,7 +743,8 @@ public class TouchExplorer extends BaseEventStreamTransformation */ private void handleMotionEventStateDragging( MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { // Multi-finger gestures conflict with this functionality. return; } @@ -723,7 +786,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case 2: { if (isDraggingGesture(event)) { // If still dragging send a drag event. - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_MOVE, @@ -734,6 +797,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // The two pointers are moving either in different directions or // no close enough => delegate the gesture to the view hierarchy. mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; // Remove move history before send injected non-move events event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. @@ -749,6 +813,7 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; default: { mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( @@ -772,17 +837,15 @@ public class TouchExplorer extends BaseEventStreamTransformation } } break; case MotionEvent.ACTION_UP: { - mAms.onTouchInteractionEnd(); - // Announce the end of a new touch interaction. - mDispatcher.sendAccessibilityEvent( - AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); final int pointerId = event.getPointerId(event.getActionIndex()); if (pointerId == mDraggingPointerId) { - mDraggingPointerId = INVALID_POINTER_ID; - // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); } + mAms.onTouchInteractionEnd(); + // Announce the end of a new touch interaction. + mDispatcher.sendAccessibilityEvent( + AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); } break; } } @@ -901,21 +964,104 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag The new location will be in - * between the two fingers touching the screen. + * Computes {@link #mDraggingPointerId} if it is invalid. The pointer will be the finger + * closet to an edge of the screen. */ - private void adjustEventLocationForDrag(MotionEvent event) { - + private void computeDraggingPointerIdIfNeeded(MotionEvent event) { + if (mDraggingPointerId != INVALID_POINTER_ID) { + // If we have a valid pointer ID, we should be good + final int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (event.findPointerIndex(pointerIndex) >= 0) { + return; + } + } + // Use the pointer that is closest to its closest edge. final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); + final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); - final int pointerIndex = event.findPointerIndex(mDraggingPointerId); - final float deltaX = - (pointerIndex == 0) ? (secondPtrX - firstPtrX) : (firstPtrX - secondPtrX); - final float deltaY = - (pointerIndex == 0) ? (secondPtrY - firstPtrY) : (firstPtrY - secondPtrY); - event.offsetLocation(deltaX / 2, deltaY / 2); + final int secondPtrId = event.getPointerId(1); + mDraggingPointerId = (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) + ? firstPtrId : secondPtrId; + } + + private float getDistanceToClosestEdge(float x, float y) { + final long width = mContext.getResources().getDisplayMetrics().widthPixels; + final long height = mContext.getResources().getDisplayMetrics().heightPixels; + float distance = Float.MAX_VALUE; + if (x < (width - x)) { + distance = x; + } else { + distance = width - x; + } + if (distance > y) { + distance = y; + } + if (distance > (height - y)) { + distance = (height - y); + } + return distance; + } + + /** + * Creates a down event using the down coordinates of the dragging pointer and other information + * from the supplied event. The supplied event's down time is adjusted to reflect the time when + * the dragging pointer initially went down. + */ + private MotionEvent computeDownEventForDrag(MotionEvent event) { + // Creating a down event only makes sense if we haven't started touch exploring yet. + if (mState.isTouchExploring() + || mDraggingPointerId == INVALID_POINTER_ID + || event == null) { + return null; + } + final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId); + final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId); + final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId); + MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1]; + coords[0] = new MotionEvent.PointerCoords(); + coords[0].x = x; + coords[0].y = y; + MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1]; + properties[0] = new MotionEvent.PointerProperties(); + properties[0].id = mDraggingPointerId; + properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER; + MotionEvent downEvent = + MotionEvent.obtain( + time, + time, + MotionEvent.ACTION_DOWN, + 1, + properties, + coords, + event.getMetaState(), + event.getButtonState(), + event.getXPrecision(), + event.getYPrecision(), + event.getDeviceId(), + event.getEdgeFlags(), + event.getSource(), + event.getFlags()); + event.setDownTime(time); + return downEvent; + } + + private boolean allPointersDownOnBottomEdge(MotionEvent event) { + final long screenHeight = + mContext.getResources().getDisplayMetrics().heightPixels; + for (int i = 0; i < event.getPointerCount(); ++i) { + final int pointerId = event.getPointerId(i); + final float pointerDownY = mReceivedPointerTracker.getReceivedPointerDownY(pointerId); + if (pointerDownY < (screenHeight - mEdgeSwipeHeightPixels)) { + if (DEBUG) { + Slog.d(LOG_TAG, "The pointer is not on the bottom edge" + pointerDownY); + } + return false; + } + } + return true; } public TouchState getState() { @@ -944,6 +1090,13 @@ public class TouchExplorer extends BaseEventStreamTransformation mGestureDetector.setMultiFingerGesturesEnabled(enabled); } + /** + * This function turns on and off two-finger passthrough gestures such as drag and pinch when + * multi-finger gestures are enabled. + */ + public void setTwoFingerPassthroughEnabled(boolean enabled) { + mGestureDetector.setTwoFingerPassthroughEnabled(enabled); + } public void setGestureDetectionPassthroughRegion(Region region) { mGestureDetectionPassthroughRegion = region; } @@ -953,7 +1106,7 @@ public class TouchExplorer extends BaseEventStreamTransformation } private boolean shouldPerformGestureDetection(MotionEvent event) { - if (mState.isDelegating()) { + if (mState.isDelegating() || mState.isDragging()) { return false; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { @@ -1046,6 +1199,15 @@ public class TouchExplorer extends BaseEventStreamTransformation } public void run() { + if (mReceivedPointerTracker.getReceivedPointerDownCount() > 1) { + // Multi-finger touch exploration doesn't make sense. + Slog.e( + LOG_TAG, + "Attempted touch exploration with " + + mReceivedPointerTracker.getReceivedPointerDownCount() + + " pointers down."); + return; + } // Send an accessibility event to announce the touch exploration start. mDispatcher.sendAccessibilityEvent( AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START); diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java index 7a39bc29e8e5..6dabe76c7dc9 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java @@ -208,7 +208,9 @@ public class TouchState { startGestureDetecting(); break; case AccessibilityEvent.TYPE_GESTURE_DETECTION_END: - startTouchInteracting(); + // Clear to make sure that we don't accidentally execute passthrough, and that we + // are ready for the next interaction. + clear(); break; default: break; diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index a704c58a9b70..ad91924c1e63 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -300,6 +300,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind mFindDeviceCallback = callback; mRequest = request; mCallingPackage = callingPackage; + request.setCallingPackage(callingPackage); callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0); final long callingIdentity = Binder.clearCallingIdentity(); @@ -308,7 +309,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind AndroidFuture<Association> future = new AndroidFuture<>(); service.startDiscovery(request, callingPackage, callback, future); return future; - }).whenComplete(uncheckExceptions((association, err) -> { + }).cancelTimeout().whenComplete(uncheckExceptions((association, err) -> { if (err == null) { addAssociation(association); } else { @@ -372,7 +373,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind checkArgument(getCallingUserId() == userId, "Must be called by either same user or system"); - mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); + int callingUid = Binder.getCallingUid(); + if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) { + throw new SecurityException(pkg + " doesn't belong to uid " + callingUid); + } } @Override @@ -561,7 +565,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind if (DEBUG) { Log.i(LOG_TAG, "recordAssociation(" + association + ")"); } - updateAssociations(associations -> CollectionUtils.add(associations, association)); + updateAssociations(associations -> CollectionUtils.add(associations, association), + association.userId); } private void recordAssociation(String privilegedPackage, String deviceAddress) { diff --git a/services/core/Android.bp b/services/core/Android.bp index 4b9d0f1266f5..f6326eb0d78a 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -1,4 +1,11 @@ filegroup { + name: "services.core-sources-deviceconfig-interface", + srcs: [ + "java/com/android/server/utils/DeviceConfigInterface.java" + ], +} + +filegroup { name: "services.core-sources", srcs: ["java/**/*.java"], exclude_srcs: [":connectivity-service-srcs"], diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 1cdc95a46f81..eb1123e47f52 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -315,11 +315,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>> mPreciseDataConnectionStates; - static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = - PhoneStateListener.LISTEN_REGISTRATION_FAILURE - | PhoneStateListener.LISTEN_BARRING_INFO; - - static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK = + // Starting in Q, almost all cellular location requires FINE location enforcement. + // Prior to Q, cellular was available with COARSE location enforcement. Bits in this + // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later. + static final int ENFORCE_LOCATION_PERMISSION_MASK = PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_CELL_INFO | PhoneStateListener.LISTEN_REGISTRATION_FAILURE @@ -376,7 +375,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + " newDefaultPhoneId=" + newDefaultPhoneId); } - //Due to possible risk condition,(notify call back using the new + //Due to possible race condition,(notify call back using the new //defaultSubId comes before new defaultSubId update) we need to recall all //possible missed notify callback synchronized (mRecords) { @@ -909,7 +908,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } @@ -964,7 +964,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " + mCellInfo.get(phoneId)); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -1518,7 +1519,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo @@ -1797,7 +1799,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellLocation: cellIdentity=" + cellIdentity @@ -2542,19 +2545,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .setCallingPid(Binder.getCallingPid()) .setCallingUid(Binder.getCallingUid()); - boolean shouldCheckLocationPermissions = false; - if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) { - locationQueryBuilder.setMinSdkVersionForCoarse(0); - shouldCheckLocationPermissions = true; - } - - if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) { + if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) { // Everything that requires fine location started in Q. So far... locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q); - shouldCheckLocationPermissions = true; - } + // If we're enforcing fine starting in Q, we also want to enforce coarse even for + // older SDK versions. + locationQueryBuilder.setMinSdkVersionForCoarse(0); - if (shouldCheckLocationPermissions) { LocationAccessPolicy.LocationPermissionResult result = LocationAccessPolicy.checkLocationPermission( mContext, locationQueryBuilder.build()); @@ -2721,8 +2718,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" + mServiceState[phoneId]); - r.callback.onServiceStateChanged( - new ServiceState(mServiceState[phoneId])); + ServiceState ss = new ServiceState(mServiceState[phoneId]); + if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged(ss); + } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged( + ss.createLocationInfoSanitizedCopy(false)); + } else { + r.callback.onServiceStateChanged( + ss.createLocationInfoSanitizedCopy(true)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2767,7 +2772,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " + mCellInfo.get(phoneId)); } - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -2833,7 +2839,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = " + mCellIdentity[phoneId]); } - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index daae1a11059c..4ff6dac08b85 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -327,6 +327,13 @@ final class UiModeManagerService extends SystemService { mCurrentUser = userHandle; getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver); verifySetupWizardCompleted(); + synchronized (mLock) { + // only update if the value is actually changed + if (updateNightModeFromSettingsLocked(getContext(), getContext().getResources(), + mCurrentUser)) { + updateLocked(0, 0); + } + } } @Override @@ -354,11 +361,10 @@ final class UiModeManagerService extends SystemService { new IntentFilter(Intent.ACTION_DOCK_EVENT)); IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); context.registerReceiver(mBatteryReceiver, batteryFilter); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_SWITCHED); context.registerReceiver(mSettingsRestored, new IntentFilter(Intent.ACTION_SETTING_RESTORED)); - context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler); + context.registerReceiver(mOnShutdown, + new IntentFilter(Intent.ACTION_SHUTDOWN)); updateConfigurationLocked(); applyConfigurationExternallyLocked(); } @@ -405,6 +411,21 @@ final class UiModeManagerService extends SystemService { publishLocalService(UiModeManagerInternal.class, mLocalService); } + private final BroadcastReceiver mOnShutdown = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mNightMode == MODE_NIGHT_AUTO) { + persistComputedNightMode(mCurrentUser); + } + } + }; + + private void persistComputedNightMode(int userId) { + Secure.putIntForUser(getContext().getContentResolver(), + Secure.UI_NIGHT_MODE_LAST_COMPUTED, mComputedNightMode ? 1 : 0, + userId); + } + private final BroadcastReceiver mSettingsRestored = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -506,6 +527,10 @@ final class UiModeManagerService extends SystemService { Secure.getLongForUser(context.getContentResolver(), Secure.DARK_THEME_CUSTOM_END_TIME, DEFAULT_CUSTOM_NIGHT_END_TIME.toNanoOfDay() / 1000L, userId) * 1000); + if (mNightMode == MODE_NIGHT_AUTO) { + mComputedNightMode = Secure.getIntForUser(context.getContentResolver(), + Secure.UI_NIGHT_MODE_LAST_COMPUTED, 0, userId) != 0; + } } return oldNightMode != mNightMode; @@ -1596,18 +1621,4 @@ final class UiModeManagerService extends SystemService { } } } - - private final class UserSwitchedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mLock) { - final int currentId = intent.getIntExtra( - Intent.EXTRA_USER_HANDLE, USER_SYSTEM); - // only update if the value is actually changed - if (updateNightModeFromSettingsLocked(context, context.getResources(), currentId)) { - updateLocked(0, 0); - } - } - } - } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e4cdfe92ec8a..f134df762b52 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7142,67 +7142,68 @@ public class ActivityManagerService extends IActivityManager.Stub "getContentProviderImpl: after checkContentProviderPermission"); final long origId = Binder.clearCallingIdentity(); + try { + checkTime(startTime, "getContentProviderImpl: incProviderCountLocked"); + + // Return the provider instance right away since it already exists. + conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, + callingTag, stable); + if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { + if (cpr.proc != null + && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { + // If this is a perceptible app accessing the provider, + // make sure to count it as being accessed and thus + // back up on the LRU list. This is good because + // content providers are often expensive to start. + checkTime(startTime, "getContentProviderImpl: before updateLruProcess"); + mProcessList.updateLruProcessLocked(cpr.proc, false, null); + checkTime(startTime, "getContentProviderImpl: after updateLruProcess"); + } + } - checkTime(startTime, "getContentProviderImpl: incProviderCountLocked"); - - // In this case the provider instance already exists, so we can - // return it right away. - conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, - stable); - if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { - if (cpr.proc != null - && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { - // If this is a perceptible app accessing the provider, - // make sure to count it as being accessed and thus - // back up on the LRU list. This is good because - // content providers are often expensive to start. - checkTime(startTime, "getContentProviderImpl: before updateLruProcess"); - mProcessList.updateLruProcessLocked(cpr.proc, false, null); - checkTime(startTime, "getContentProviderImpl: after updateLruProcess"); - } - } - - checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); - final int verifiedAdj = cpr.proc.verifiedAdj; - boolean success = updateOomAdjLocked(cpr.proc, true, - OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); - // XXX things have changed so updateOomAdjLocked doesn't actually tell us - // if the process has been successfully adjusted. So to reduce races with - // it, we will check whether the process still exists. Note that this doesn't - // completely get rid of races with LMK killing the process, but should make - // them much smaller. - if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) { - success = false; - } - maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name); - checkTime(startTime, "getContentProviderImpl: after updateOomAdj"); - if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success); - // NOTE: there is still a race here where a signal could be - // pending on the process even though we managed to update its - // adj level. Not sure what to do about this, but at least - // the race is now smaller. - if (!success) { - // Uh oh... it looks like the provider's process - // has been killed on us. We need to wait for a new - // process to be started, and make sure its death - // doesn't kill our process. - Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString() - + " is crashing; detaching " + r); - boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); - if (!lastRef) { - // This wasn't the last ref our process had on - // the provider... we will be killed during cleaning up, bail. - return null; + checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); + final int verifiedAdj = cpr.proc.verifiedAdj; + boolean success = updateOomAdjLocked(cpr.proc, true, + OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER); + // XXX things have changed so updateOomAdjLocked doesn't actually tell us + // if the process has been successfully adjusted. So to reduce races with + // it, we will check whether the process still exists. Note that this doesn't + // completely get rid of races with LMK killing the process, but should make + // them much smaller. + if (success && verifiedAdj != cpr.proc.setAdj + && !isProcessAliveLocked(cpr.proc)) { + success = false; + } + maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name); + checkTime(startTime, "getContentProviderImpl: after updateOomAdj"); + if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success); + // NOTE: there is still a race here where a signal could be + // pending on the process even though we managed to update its + // adj level. Not sure what to do about this, but at least + // the race is now smaller. + if (!success) { + // Uh oh... it looks like the provider's process + // has been killed on us. We need to wait for a new + // process to be started, and make sure its death + // doesn't kill our process. + Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString() + + " is crashing; detaching " + r); + boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); + if (!lastRef) { + // This wasn't the last ref our process had on + // the provider... we will be killed during cleaning up, bail. + return null; + } + // We'll just start a new process to host the content provider + providerRunning = false; + conn = null; + dyingProc = cpr.proc; + } else { + cpr.proc.verifiedAdj = cpr.proc.setAdj; } - // We'll just start a new process to host the content provider - providerRunning = false; - conn = null; - dyingProc = cpr.proc; - } else { - cpr.proc.verifiedAdj = cpr.proc.setAdj; + } finally { + Binder.restoreCallingIdentity(origId); } - - Binder.restoreCallingIdentity(origId); } if (!providerRunning) { @@ -10459,12 +10460,10 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - if (uid == Process.INVALID_UID) { - return Process.INVALID_UID; - } + // If the uid is Process.INVALID_UID, the below 'if' check will be always true if (UserHandle.getAppId(uid) != UserHandle.getAppId(callingUid)) { // Requires the DUMP permission if the target package doesn't belong - // to the caller. + // to the caller or it doesn't exist. enforceCallingPermission(android.Manifest.permission.DUMP, function); } return uid; diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index a2eea1348d5c..9a6f130cfd5d 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -791,7 +791,10 @@ public final class BroadcastQueue { mService.updateOomAdjLocked(r.curApp, true, OomAdjuster.OOM_ADJ_REASON_START_RECEIVER); } + } else if (filter.receiverList.app != null) { + mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app); } + try { if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, "Delivering to " + filter + " : " + r); @@ -1121,6 +1124,10 @@ public final class BroadcastQueue { } } if (sendResult) { + if (r.callerApp != null) { + mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily( + r.callerApp); + } try { if (DEBUG_BROADCAST) { Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] " diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 8112bb854b71..36d4a38c1624 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -720,6 +720,16 @@ public final class CachedAppOptimizer { } } + // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS + void unfreezeTemporarily(ProcessRecord app) { + synchronized (mAm) { + if (app.frozen) { + unfreezeAppLocked(app); + freezeAppAsync(app); + } + } + } + @GuardedBy("mAm") void freezeAppAsync(ProcessRecord app) { mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); @@ -777,27 +787,27 @@ public final class CachedAppOptimizer { long freezeTime = app.freezeUnfreezeTime; try { + freezeBinder(app.pid, false); + } catch (RuntimeException e) { + Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName + + ". Killing it"); + app.kill("Unable to unfreeze", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_INVALID_STATE, true); + return; + } + + try { Process.setProcessFrozen(app.pid, app.uid, false); app.freezeUnfreezeTime = SystemClock.uptimeMillis(); app.frozen = false; } catch (Exception e) { Slog.e(TAG_AM, "Unable to unfreeze " + app.pid + " " + app.processName - + ". Any related user experience might be hanged."); + + ". This might cause inconsistency or UI hangs."); } if (!app.frozen) { - try { - freezeBinder(app.pid, false); - } catch (RuntimeException e) { - Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName - + ". Killing it"); - app.kill("Unable to unfreeze", - ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_INVALID_STATE, true); - return; - } - if (DEBUG_FREEZER) { Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName); } @@ -1110,14 +1120,6 @@ public final class CachedAppOptimizer { return; } - try { - freezeBinder(pid, true); - } catch (RuntimeException e) { - // TODO: it might be preferable to kill the target pid in this case - Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); - return; - } - if (pid == 0 || proc.frozen) { // Already frozen or not a real process, either one being // launched or one being killed @@ -1146,6 +1148,15 @@ public final class CachedAppOptimizer { EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name); + try { + freezeBinder(pid, true); + } catch (RuntimeException e) { + Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); + proc.kill("Unable to freeze binder interface", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_INVALID_STATE, true); + } + // See above for why we're not taking mPhenotypeFlagLock here if (mRandom.nextFloat() < mFreezerStatsdSampleRate) { FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED, diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 640d99f71ebe..46255f5dac27 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1011,10 +1011,11 @@ public class AppOpsService extends IAppOpsService.Stub { } int numInProgressEvents = mInProgressEvents.size(); + List<IBinder> binders = new ArrayList<>(mInProgressEvents.keySet()); for (int i = 0; i < numInProgressEvents; i++) { - InProgressStartOpEvent event = mInProgressEvents.valueAt(i); + InProgressStartOpEvent event = mInProgressEvents.get(binders.get(i)); - if (event.getUidState() != newState) { + if (event != null && event.getUidState() != newState) { try { // Remove all but one unfinished start count and then call finished() to // remove start event object @@ -1025,7 +1026,10 @@ public class AppOpsService extends IAppOpsService.Stub { // Call started() to add a new start event object and then add the // previously removed unfinished start counts back started(event.getClientId(), newState, false); - event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1; + InProgressStartOpEvent newEvent = mInProgressEvents.get(binders.get(i)); + if (newEvent != null) { + newEvent.numUnfinishedStarts += numPreviousUnfinishedStarts - 1; + } } catch (RemoteException e) { if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState); } @@ -2989,9 +2993,14 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } + // This is a workaround for R QPR, new API change is not allowed. We only allow the current + // voice recognizer is also the voice interactor to noteproxy op. + final boolean isTrustVoiceServiceProxy = + AppOpsManager.isTrustedVoiceServiceProxy(mContext, proxyPackageName, code); + final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isProxyTrusted = mContext.checkPermission( Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) - == PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy || isSelfBlame; final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY; diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 3d22a156b91c..f49b5dca2b08 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -669,10 +669,12 @@ final class HistoricalRegistry { void shutdown() { synchronized (mInMemoryLock) { - if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) { - persistPendingHistory(); + if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { + return; } } + // Do not call persistPendingHistory inside the memory lock, due to possible deadlock + persistPendingHistory(); } void persistPendingHistory() { diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index ef1b574c29a8..b4d74e0900f9 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -148,7 +154,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List<ActivityManager.RunningTaskInfo> tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index a0eafb4fc93f..b7e188c73eab 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -392,6 +392,7 @@ class RadioModule { } catch (RemoteException ex) { Slog.e(TAG, "Failed closing announcement listener", ex); } + hwCloseHandle.value = null; } }; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 24661d69a78e..852868616afd 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -86,6 +86,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; +import android.util.EventLog; import android.util.IntArray; import android.util.Pair; import android.util.Slog; @@ -2191,10 +2192,16 @@ public final class DisplayManagerService extends SystemService { } } - if (callingUid == Process.SYSTEM_UID - || checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { - flags |= VIRTUAL_DISPLAY_FLAG_TRUSTED; - } else { + if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { + if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { + EventLog.writeEvent(0x534e4554, "162627132", callingUid, + "Attempt to create a trusted display without holding permission!"); + throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + + "create a trusted virtual display."); + } + } + + if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index baa43cfd92f1..e30b1ebdbe2a 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -46,8 +46,10 @@ import android.view.DisplayInfo; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.display.utils.AmbientFilter; import com.android.server.display.utils.AmbientFilterFactory; +import com.android.server.utils.DeviceConfigInterface; import java.io.PrintWriter; import java.util.ArrayList; @@ -64,9 +66,11 @@ public class DisplayModeDirector { private static final boolean DEBUG = false; private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1; - private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; + private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; - private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4; + private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4; + private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5; + private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6; // Special ID used to indicate that given vote is to be applied globally, rather than to a // specific display. @@ -79,6 +83,13 @@ public class DisplayModeDirector { private final Context mContext; private final DisplayModeDirectorHandler mHandler; + private final Injector mInjector; + + private final AppRequestObserver mAppRequestObserver; + private final SettingsObserver mSettingsObserver; + private final DisplayObserver mDisplayObserver; + private final DeviceConfigInterface mDeviceConfig; + private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; // A map from the display ID to the collection of votes and their priority. The latter takes // the form of another map from the priority to the vote itself so that each priority is @@ -89,17 +100,19 @@ public class DisplayModeDirector { // A map from the display ID to the default mode of that display. private SparseArray<Display.Mode> mDefaultModeByDisplay; - private final AppRequestObserver mAppRequestObserver; - private final SettingsObserver mSettingsObserver; - private final DisplayObserver mDisplayObserver; private BrightnessObserver mBrightnessObserver; - private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { + this(context, handler, new RealInjector()); + } + + public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, + @NonNull Injector injector) { mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); + mInjector = injector; mVotesByDisplay = new SparseArray<>(); mSupportedModesByDisplay = new SparseArray<>(); mDefaultModeByDisplay = new SparseArray<>(); @@ -108,6 +121,7 @@ public class DisplayModeDirector { mDisplayObserver = new DisplayObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); + mDeviceConfig = injector.getDeviceConfig(); } /** @@ -348,6 +362,23 @@ public class DisplayModeDirector { } /** + * Retrieve the Vote for the given display and priority. Intended only for testing purposes. + * + * @param displayId the display to query for + * @param priority the priority of the vote to return + * @return the vote corresponding to the given {@code displayId} and {@code priority}, + * or {@code null} if there isn't one + */ + @VisibleForTesting + @Nullable + Vote getVote(int displayId, int priority) { + synchronized (mLock) { + SparseArray<Vote> votes = getVotesLocked(displayId); + return votes.get(priority); + } + } + + /** * Print the object's state and debug information into the given stream. * * @param pw The stream to dump information to. @@ -465,6 +496,17 @@ public class DisplayModeDirector { } @VisibleForTesting + BrightnessObserver getBrightnessObserver() { + return mBrightnessObserver; + } + + @VisibleForTesting + SettingsObserver getSettingsObserver() { + return mSettingsObserver; + } + + + @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { synchronized (mLock) { @@ -492,16 +534,35 @@ public class DisplayModeDirector { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_BRIGHTNESS_THRESHOLDS_CHANGED: + case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: { + Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj; + mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged( + thresholds.first, thresholds.second); + break; + } + + case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: { + int refreshRateInZone = msg.arg1; + mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged( + refreshRateInZone); + break; + } + + case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: { Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj; - if (thresholds != null) { - mBrightnessObserver.onDeviceConfigThresholdsChanged( - thresholds.first, thresholds.second); - } else { - mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null); - } + mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged( + thresholds.first, thresholds.second); + + break; + } + + case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: { + int refreshRateInZone = msg.arg1; + mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged( + refreshRateInZone); break; + } case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED: Float defaultPeakRefreshRate = (Float) msg.obj; @@ -509,12 +570,6 @@ public class DisplayModeDirector { defaultPeakRefreshRate); break; - case MSG_REFRESH_RATE_IN_ZONE_CHANGED: - int refreshRateInZone = msg.arg1; - mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged( - refreshRateInZone); - break; - case MSG_REFRESH_RATE_RANGE_CHANGED: DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener = (DesiredDisplayModeSpecsListener) msg.obj; @@ -684,10 +739,11 @@ public class DisplayModeDirector { // by all other considerations. It acts to set a default frame rate for a device. public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0; - // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null. + // FLICKER votes for a single refresh rate like [60,60], [90,90] or null. // If the higher voters result is a range, it will fix the rate to a single choice. - // It's used to avoid rate switch in certain conditions. - public static final int PRIORITY_LOW_BRIGHTNESS = 1; + // It's used to avoid refresh rate switches in certain conditions which may result in the + // user seeing the display flickering when the switches occur. + public static final int PRIORITY_FLICKER = 1; // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate. // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY] @@ -760,8 +816,8 @@ public class DisplayModeDirector { switch (priority) { case PRIORITY_DEFAULT_REFRESH_RATE: return "PRIORITY_DEFAULT_REFRESH_RATE"; - case PRIORITY_LOW_BRIGHTNESS: - return "PRIORITY_LOW_BRIGHTNESS"; + case PRIORITY_FLICKER: + return "PRIORITY_FLICKER"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_REFRESH_RATE: @@ -786,7 +842,8 @@ public class DisplayModeDirector { } } - private final class SettingsObserver extends ContentObserver { + @VisibleForTesting + final class SettingsObserver extends ContentObserver { private final Uri mPeakRefreshRateSetting = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); private final Uri mMinRefreshRateSetting = @@ -809,8 +866,7 @@ public class DisplayModeDirector { public void observe() { final ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this, - UserHandle.USER_SYSTEM); + mInjector.registerPeakRefreshRateObserver(cr, this); cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this, @@ -828,6 +884,13 @@ public class DisplayModeDirector { } } + public void setDefaultRefreshRate(float refreshRate) { + synchronized (mLock) { + mDefaultRefreshRate = refreshRate; + updateRefreshRateSettingLocked(); + } + } + public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) { if (defaultPeakRefreshRate == null) { defaultPeakRefreshRate = (float) mContext.getResources().getInteger( @@ -1032,6 +1095,7 @@ public class DisplayModeDirector { @Override public void onDisplayChanged(int displayId) { updateDisplayModes(displayId); + // TODO: Break the coupling between DisplayObserver and BrightnessObserver. mBrightnessObserver.onDisplayChanged(displayId); } @@ -1070,15 +1134,16 @@ public class DisplayModeDirector { */ @VisibleForTesting public class BrightnessObserver extends ContentObserver { - // TODO: brightnessfloat: change this to the float setting - private final Uri mDisplayBrightnessSetting = - Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); private final static int LIGHT_SENSOR_RATE_MS = 250; - private int[] mDisplayBrightnessThresholds; - private int[] mAmbientBrightnessThresholds; + private int[] mLowDisplayBrightnessThresholds; + private int[] mLowAmbientBrightnessThresholds; + private int[] mHighDisplayBrightnessThresholds; + private int[] mHighAmbientBrightnessThresholds; // valid threshold if any item from the array >= 0 - private boolean mShouldObserveDisplayChange; - private boolean mShouldObserveAmbientChange; + private boolean mShouldObserveDisplayLowChange; + private boolean mShouldObserveAmbientLowChange; + private boolean mShouldObserveDisplayHighChange; + private boolean mShouldObserveAmbientHighChange; private SensorManager mSensorManager; private Sensor mLightSensor; @@ -1086,46 +1151,122 @@ public class DisplayModeDirector { // Take it as low brightness before valid sensor data comes private float mAmbientLux = -1.0f; private AmbientFilter mAmbientFilter; + private int mBrightness = -1; private final Context mContext; - // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak - // refresh rate changeable and low power mode off. After initialization, these states will + // Enable light sensor only when mShouldObserveAmbientLowChange is true or + // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate + // changeable and low power mode off. After initialization, these states will // be updated from the same handler thread. - private boolean mScreenOn = false; + private boolean mDefaultDisplayOn = false; private boolean mRefreshRateChangeable = false; private boolean mLowPowerModeEnabled = false; - private int mRefreshRateInZone; + private int mRefreshRateInLowZone; + private int mRefreshRateInHighZone; BrightnessObserver(Context context, Handler handler) { super(handler); mContext = context; - mDisplayBrightnessThresholds = context.getResources().getIntArray( + mLowDisplayBrightnessThresholds = context.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); - mAmbientBrightnessThresholds = context.getResources().getIntArray( + mLowAmbientBrightnessThresholds = context.getResources().getIntArray( R.array.config_ambientThresholdsOfPeakRefreshRate); - if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) { - throw new RuntimeException("display brightness threshold array and ambient " - + "brightness threshold array have different length"); + if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) { + throw new RuntimeException("display low brightness threshold array and ambient " + + "brightness threshold array have different length: " + + "displayBrightnessThresholds=" + + Arrays.toString(mLowDisplayBrightnessThresholds) + + ", ambientBrightnessThresholds=" + + Arrays.toString(mLowAmbientBrightnessThresholds)); } + + mHighDisplayBrightnessThresholds = context.getResources().getIntArray( + R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate); + mHighAmbientBrightnessThresholds = context.getResources().getIntArray( + R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate); + if (mHighDisplayBrightnessThresholds.length + != mHighAmbientBrightnessThresholds.length) { + throw new RuntimeException("display high brightness threshold array and ambient " + + "brightness threshold array have different length: " + + "displayBrightnessThresholds=" + + Arrays.toString(mHighDisplayBrightnessThresholds) + + ", ambientBrightnessThresholds=" + + Arrays.toString(mHighAmbientBrightnessThresholds)); + } + mRefreshRateInHighZone = context.getResources().getInteger( + R.integer.config_fixedRefreshRateInHighZone); + } + + /** + * @return the refresh to lock to when in a low brightness zone + */ + @VisibleForTesting + int getRefreshRateInLowZone() { + return mRefreshRateInLowZone; + } + + /** + * @return the display brightness thresholds for the low brightness zones + */ + @VisibleForTesting + int[] getLowDisplayBrightnessThresholds() { + return mLowDisplayBrightnessThresholds; + } + + /** + * @return the ambient brightness thresholds for the low brightness zones + */ + @VisibleForTesting + int[] getLowAmbientBrightnessThresholds() { + return mLowAmbientBrightnessThresholds; + } + + public void registerLightSensor(SensorManager sensorManager, Sensor lightSensor) { + mSensorManager = sensorManager; + mLightSensor = lightSensor; + + mSensorManager.registerListener(mLightSensorListener, + mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); } public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; + final ContentResolver cr = mContext.getContentResolver(); + mBrightness = Settings.System.getIntForUser(cr, + Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); // DeviceConfig is accessible after system ready. - int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); - int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); + int[] lowDisplayBrightnessThresholds = + mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(); + int[] lowAmbientBrightnessThresholds = + mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(); + + if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null + && lowDisplayBrightnessThresholds.length + == lowAmbientBrightnessThresholds.length) { + mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds; + mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds; + } - if (brightnessThresholds != null && ambientThresholds != null - && brightnessThresholds.length == ambientThresholds.length) { - mDisplayBrightnessThresholds = brightnessThresholds; - mAmbientBrightnessThresholds = ambientThresholds; + + int[] highDisplayBrightnessThresholds = + mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(); + int[] highAmbientBrightnessThresholds = + mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(); + + if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null + && highDisplayBrightnessThresholds.length + == highAmbientBrightnessThresholds.length) { + mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds; + mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds; } - mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone(); + mRefreshRateInLowZone = mDeviceConfigDisplaySettings.getRefreshRateInLowZone(); + mRefreshRateInHighZone = mDeviceConfigDisplaySettings.getRefreshRateInHighZone(); + restartObserver(); mDeviceConfigDisplaySettings.startListening(); } @@ -1137,7 +1278,7 @@ public class DisplayModeDirector { updateSensorStatus(); if (!changeable) { // Revoke previous vote from BrightnessObserver - updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null); + updateVoteLocked(Vote.PRIORITY_FLICKER, null); } } } @@ -1149,25 +1290,48 @@ public class DisplayModeDirector { } } - public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds, + public void onDeviceConfigLowBrightnessThresholdsChanged(int[] displayThresholds, int[] ambientThresholds) { - if (brightnessThresholds != null && ambientThresholds != null - && brightnessThresholds.length == ambientThresholds.length) { - mDisplayBrightnessThresholds = brightnessThresholds; - mAmbientBrightnessThresholds = ambientThresholds; + if (displayThresholds != null && ambientThresholds != null + && displayThresholds.length == ambientThresholds.length) { + mLowDisplayBrightnessThresholds = displayThresholds; + mLowAmbientBrightnessThresholds = ambientThresholds; } else { // Invalid or empty. Use device default. - mDisplayBrightnessThresholds = mContext.getResources().getIntArray( + mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); - mAmbientBrightnessThresholds = mContext.getResources().getIntArray( + mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray( R.array.config_ambientThresholdsOfPeakRefreshRate); } restartObserver(); } - public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) { - if (refreshRate != mRefreshRateInZone) { - mRefreshRateInZone = refreshRate; + public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) { + if (refreshRate != mRefreshRateInLowZone) { + mRefreshRateInLowZone = refreshRate; + restartObserver(); + } + } + + public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds, + int[] ambientThresholds) { + if (displayThresholds != null && ambientThresholds != null + && displayThresholds.length == ambientThresholds.length) { + mHighDisplayBrightnessThresholds = displayThresholds; + mHighAmbientBrightnessThresholds = ambientThresholds; + } else { + // Invalid or empty. Use device default. + mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate); + mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate); + } + restartObserver(); + } + + public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) { + if (refreshRate != mRefreshRateInHighZone) { + mRefreshRateInHighZone = refreshRate; restartObserver(); } } @@ -1175,48 +1339,95 @@ public class DisplayModeDirector { public void dumpLocked(PrintWriter pw) { pw.println(" BrightnessObserver"); pw.println(" mAmbientLux: " + mAmbientLux); - pw.println(" mRefreshRateInZone: " + mRefreshRateInZone); + pw.println(" mBrightness: " + mBrightness); + pw.println(" mDefaultDisplayOn: " + mDefaultDisplayOn); + pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled); + pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable); + pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange); + pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange); + pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone); - for (int d: mDisplayBrightnessThresholds) { - pw.println(" mDisplayBrightnessThreshold: " + d); + for (int d : mLowDisplayBrightnessThresholds) { + pw.println(" mDisplayLowBrightnessThreshold: " + d); } - for (int d: mAmbientBrightnessThresholds) { - pw.println(" mAmbientBrightnessThreshold: " + d); + for (int d : mLowAmbientBrightnessThresholds) { + pw.println(" mAmbientLowBrightnessThreshold: " + d); + } + + pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange); + pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange); + pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone); + + for (int d : mHighDisplayBrightnessThresholds) { + pw.println(" mDisplayHighBrightnessThresholds: " + d); + } + + for (int d : mHighAmbientBrightnessThresholds) { + pw.println(" mAmbientHighBrightnessThresholds: " + d); } mLightSensorListener.dumpLocked(pw); + + if (mAmbientFilter != null) { + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + ipw.setIndent(" "); + mAmbientFilter.dump(ipw); + } } public void onDisplayChanged(int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { - onScreenOn(isDefaultDisplayOn()); + updateDefaultDisplayState(); } } @Override public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { - onBrightnessChangedLocked(); + final ContentResolver cr = mContext.getContentResolver(); + int brightness = Settings.System.getIntForUser(cr, + Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId()); + if (brightness != mBrightness) { + mBrightness = brightness; + onBrightnessChangedLocked(); + } } } private void restartObserver() { - mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds); - mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds); - final ContentResolver cr = mContext.getContentResolver(); - if (mShouldObserveDisplayChange) { + + if (mRefreshRateInLowZone > 0) { + mShouldObserveDisplayLowChange = hasValidThreshold( + mLowDisplayBrightnessThresholds); + mShouldObserveAmbientLowChange = hasValidThreshold( + mLowAmbientBrightnessThresholds); + } else { + mShouldObserveDisplayLowChange = false; + mShouldObserveAmbientLowChange = false; + } + + if (mRefreshRateInHighZone > 0) { + mShouldObserveDisplayHighChange = hasValidThreshold( + mHighDisplayBrightnessThresholds); + mShouldObserveAmbientHighChange = hasValidThreshold( + mHighAmbientBrightnessThresholds); + } else { + mShouldObserveDisplayHighChange = false; + mShouldObserveAmbientHighChange = false; + } + + if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) { // Content Service does not check if an listener has already been registered. // To ensure only one listener is registered, force an unregistration first. - cr.unregisterContentObserver(this); - cr.registerContentObserver(mDisplayBrightnessSetting, - false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); + mInjector.unregisterBrightnessObserver(cr, this); + mInjector.registerBrightnessObserver(cr, this); } else { - cr.unregisterContentObserver(this); + mInjector.unregisterBrightnessObserver(cr, this); } - if (mShouldObserveAmbientChange) { + if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) { Resources resources = mContext.getResources(); String lightSensorType = resources.getString( com.android.internal.R.string.config_displayLightSensorType); @@ -1242,8 +1453,6 @@ public class DisplayModeDirector { mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res); mLightSensor = lightSensor; - - onScreenOn(isDefaultDisplayOn()); } } else { mAmbientFilter = null; @@ -1262,11 +1471,7 @@ public class DisplayModeDirector { * Checks to see if at least one value is positive, in which case it is necessary to listen * to value changes. */ - private boolean checkShouldObserve(int[] a) { - if (mRefreshRateInZone <= 0) { - return false; - } - + private boolean hasValidThreshold(int[] a) { for (int d: a) { if (d >= 0) { return true; @@ -1276,13 +1481,13 @@ public class DisplayModeDirector { return false; } - private boolean isInsideZone(int brightness, float lux) { - for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { - int disp = mDisplayBrightnessThresholds[i]; - int ambi = mAmbientBrightnessThresholds[i]; + private boolean isInsideLowZone(int brightness, float lux) { + for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) { + int disp = mLowDisplayBrightnessThresholds[i]; + int ambi = mLowAmbientBrightnessThresholds[i]; if (disp >= 0 && ambi >= 0) { - if (brightness <= disp && mAmbientLux <= ambi) { + if (brightness <= disp && lux <= ambi) { return true; } } else if (disp >= 0) { @@ -1290,7 +1495,7 @@ public class DisplayModeDirector { return true; } } else if (ambi >= 0) { - if (mAmbientLux <= ambi) { + if (lux <= ambi) { return true; } } @@ -1298,27 +1503,77 @@ public class DisplayModeDirector { return false; } - // TODO: brightnessfloat: make it use float not int - private void onBrightnessChangedLocked() { - int brightness = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS, -1); + private boolean isInsideHighZone(int brightness, float lux) { + for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) { + int disp = mHighDisplayBrightnessThresholds[i]; + int ambi = mHighAmbientBrightnessThresholds[i]; + + if (disp >= 0 && ambi >= 0) { + if (brightness >= disp && lux >= ambi) { + return true; + } + } else if (disp >= 0) { + if (brightness >= disp) { + return true; + } + } else if (ambi >= 0) { + if (lux >= ambi) { + return true; + } + } + } + + return false; + } + private void onBrightnessChangedLocked() { Vote vote = null; - boolean insideZone = isInsideZone(brightness, mAmbientLux); - if (insideZone) { - vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone); + + if (mBrightness < 0) { + // Either the setting isn't available or we shouldn't be observing yet anyways. + // Either way, just bail out since there's nothing we can do here. + return; + } + + boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux); + if (insideLowZone) { + vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone); + } + + boolean insideHighZone = hasValidHighZone() + && isInsideHighZone(mBrightness, mAmbientLux); + if (insideHighZone) { + vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone); } if (DEBUG) { - Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + - ", Vote " + vote); + Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux + + ", Vote " + vote); } - updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); + updateVoteLocked(Vote.PRIORITY_FLICKER, vote); + } + + private boolean hasValidLowZone() { + return mRefreshRateInLowZone > 0 + && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange); + } + + private boolean hasValidHighZone() { + return mRefreshRateInHighZone > 0 + && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange); } - private void onScreenOn(boolean on) { - if (mScreenOn != on) { - mScreenOn = on; + private void updateDefaultDisplayState() { + Display display = mContext.getSystemService(DisplayManager.class) + .getDisplay(Display.DEFAULT_DISPLAY); + boolean defaultDisplayOn = display != null && display.getState() != Display.STATE_OFF; + setDefaultDisplayState(defaultDisplayOn); + } + + @VisibleForTesting + public void setDefaultDisplayState(boolean on) { + if (mDefaultDisplayOn != on) { + mDefaultDisplayOn = on; updateSensorStatus(); } } @@ -1328,8 +1583,8 @@ public class DisplayModeDirector { return; } - if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled - && mRefreshRateChangeable) { + if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) + && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) { mSensorManager.registerListener(mLightSensorListener, mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); } else { @@ -1338,11 +1593,8 @@ public class DisplayModeDirector { } } - private boolean isDefaultDisplayOn() { - final Display display = mContext.getSystemService(DisplayManager.class) - .getDisplay(Display.DEFAULT_DISPLAY); - return display.getState() != Display.STATE_OFF - && mContext.getSystemService(PowerManager.class).isInteractive(); + private boolean isDeviceActive() { + return mDefaultDisplayOn && mInjector.isDeviceInteractive(mContext); } private final class LightSensorEventListener implements SensorEventListener { @@ -1360,23 +1612,33 @@ public class DisplayModeDirector { Slog.d(TAG, "On sensor changed: " + mLastSensorData); } - boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux); - if (zoneChanged && mLastSensorData < mAmbientLux) { - // Easier to see flicker at lower brightness environment. Forget the history to - // get immediate response. - mAmbientFilter.clear(); + boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, + mLowAmbientBrightnessThresholds); + boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, + mHighAmbientBrightnessThresholds); + if ((lowZoneChanged && mLastSensorData < mAmbientLux) + || (highZoneChanged && mLastSensorData > mAmbientLux)) { + // Easier to see flicker at lower brightness environment or high brightness + // environment. Forget the history to get immediate response. + if (mAmbientFilter != null) { + mAmbientFilter.clear(); + } } long now = SystemClock.uptimeMillis(); - mAmbientFilter.addValue(now, mLastSensorData); + if (mAmbientFilter != null) { + mAmbientFilter.addValue(now, mLastSensorData); + } mHandler.removeCallbacks(mInjectSensorEventRunnable); processSensorData(now); - if (zoneChanged && mLastSensorData > mAmbientLux) { + if ((lowZoneChanged && mLastSensorData > mAmbientLux) + || (highZoneChanged && mLastSensorData < mAmbientLux)) { // Sensor may not report new event if there is no brightness change. // Need to keep querying the temporal filter for the latest estimation, - // until enter in higher lux zone or is interrupted by a new sensor event. + // until sensor readout and filter estimation are in the same zone or + // is interrupted by a new sensor event. mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); } } @@ -1391,17 +1653,19 @@ public class DisplayModeDirector { } private void processSensorData(long now) { - mAmbientLux = mAmbientFilter.getEstimate(now); + if (mAmbientFilter != null) { + mAmbientLux = mAmbientFilter.getEstimate(now); + } else { + mAmbientLux = mLastSensorData; + } synchronized (mLock) { onBrightnessChangedLocked(); } } - private boolean isDifferentZone(float lux1, float lux2) { - for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) { - final float boundary = mAmbientBrightnessThresholds[z]; - + private boolean isDifferentZone(float lux1, float lux2, int[] luxThresholds) { + for (final float boundary : luxThresholds) { // Test each boundary. See if the current value and the new value are at // different sides. if ((lux1 <= boundary && lux2 > boundary) @@ -1421,7 +1685,10 @@ public class DisplayModeDirector { processSensorData(now); // Inject next event if there is a possible zone change. - if (isDifferentZone(mLastSensorData, mAmbientLux)) { + if (isDifferentZone(mLastSensorData, mAmbientLux, + mLowAmbientBrightnessThresholds) + || isDifferentZone(mLastSensorData, mAmbientLux, + mHighAmbientBrightnessThresholds)) { mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); } } @@ -1434,72 +1701,113 @@ public class DisplayModeDirector { } public void startListening() { - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, BackgroundThread.getExecutor(), this); } /* * Return null if no such property or wrong format (not comma separated integers). */ - public int[] getBrightnessThresholds() { + public int[] getLowDisplayBrightnessThresholds() { return getIntArrayProperty( DisplayManager.DeviceConfig. - KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS); + KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS); } /* * Return null if no such property or wrong format (not comma separated integers). */ - public int[] getAmbientThresholds() { + public int[] getLowAmbientBrightnessThresholds() { return getIntArrayProperty( DisplayManager.DeviceConfig. - KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS); + KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS); + } + + public int getRefreshRateInLowZone() { + int defaultRefreshRateInZone = mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInZone); + + int refreshRate = mDeviceConfig.getInt( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE, + defaultRefreshRateInZone); + + return refreshRate; } /* - * Return null if no such property + * Return null if no such property or wrong format (not comma separated integers). */ - public Float getDefaultPeakRefreshRate() { - float defaultPeakRefreshRate = DeviceConfig.getFloat( - DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1); + public int[] getHighDisplayBrightnessThresholds() { + return getIntArrayProperty( + DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS); + } - if (defaultPeakRefreshRate == -1) { - return null; - } - return defaultPeakRefreshRate; + /* + * Return null if no such property or wrong format (not comma separated integers). + */ + public int[] getHighAmbientBrightnessThresholds() { + return getIntArrayProperty( + DisplayManager.DeviceConfig + .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS); } - public int getRefreshRateInZone() { + public int getRefreshRateInHighZone() { int defaultRefreshRateInZone = mContext.getResources().getInteger( - R.integer.config_defaultRefreshRateInZone); + R.integer.config_fixedRefreshRateInHighZone); - int refreshRate = DeviceConfig.getInt( + int refreshRate = mDeviceConfig.getInt( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE, defaultRefreshRateInZone); return refreshRate; } + /* + * Return null if no such property + */ + public Float getDefaultPeakRefreshRate() { + float defaultPeakRefreshRate = mDeviceConfig.getFloat( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1); + + if (defaultPeakRefreshRate == -1) { + return null; + } + return defaultPeakRefreshRate; + } + @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { - int[] brightnessThresholds = getBrightnessThresholds(); - int[] ambientThresholds = getAmbientThresholds(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); - int refreshRateInZone = getRefreshRateInZone(); - - mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, - new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) - .sendToTarget(); mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, defaultPeakRefreshRate).sendToTarget(); - mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone, - 0).sendToTarget(); + + int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds(); + int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds(); + int refreshRateInLowZone = getRefreshRateInLowZone(); + + mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED, + new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds)) + .sendToTarget(); + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0) + .sendToTarget(); + + int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds(); + int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds(); + int refreshRateInHighZone = getRefreshRateInHighZone(); + + mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED, + new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds)) + .sendToTarget(); + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0) + .sendToTarget(); } private int[] getIntArrayProperty(String prop) { - String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop, + String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop, null); if (strArray != null) { @@ -1526,4 +1834,59 @@ public class DisplayModeDirector { } } + interface Injector { + // TODO: brightnessfloat: change this to the float setting + Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); + Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); + + @NonNull + DeviceConfigInterface getDeviceConfig(); + + void registerBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer); + + void unregisterBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer); + + void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer); + + boolean isDeviceInteractive(@NonNull Context context); + } + + @VisibleForTesting + static class RealInjector implements Injector { + + @Override + @NonNull + public DeviceConfigInterface getDeviceConfig() { + return DeviceConfigInterface.REAL; + } + + @Override + public void registerBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/, + observer, UserHandle.USER_SYSTEM); + } + + @Override + public void unregisterBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + cr.unregisterContentObserver(observer); + } + + @Override + public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, + observer, UserHandle.USER_SYSTEM); + } + + @Override + public boolean isDeviceInteractive(@NonNull Context ctx) { + return ctx.getSystemService(PowerManager.class).isInteractive(); + } + } + } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index b6fbedb76e15..75fa9ebf693f 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3274,9 +3274,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { - if (mCurClient == null || mCurClient.curSession == null) { - return false; - } if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 && (mShowExplicitlyRequested || mShowForced)) { if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide"); diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 5c9350a8452c..3bb55a5af5c6 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -906,9 +906,26 @@ public class LocationManagerService extends ILocationManager.Stub { if (enabled == null) { // this generally shouldn't occur, but might be possible due to race conditions // on when we are notified of new users + + // hack to fix b/171910679. mutating the user enabled state within this method + // may cause unexpected changes to other state (for instance, this could cause + // provider enable/disable notifications to be sent to clients, which could + // result in a dead client being detected, which could result in the client + // being removed, which means that if this function is called while clients are + // being iterated over we have now unexpectedly mutated the iterated + // collection). instead, we return a correct value immediately here, and + // schedule the actual update for later. this has been completely rewritten and + // is no longer a problem in the next version of android. + enabled = mProvider.getState().allowed + && mUserInfoHelper.isCurrentUserId(userId) + && mSettingsHelper.isLocationEnabled(userId); + Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly"); - onEnabledChangedLocked(userId); - enabled = Objects.requireNonNull(mEnabled.get(userId)); + mHandler.post(() -> { + synchronized (mLock) { + onEnabledChangedLocked(userId); + } + }); } return enabled; diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 61f5fb878b3b..d003b89e8877 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -113,6 +113,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; @@ -2629,6 +2630,10 @@ public class LockSettingsService extends ILockSettings.Stub { protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, LockscreenCredential credential, int userId) { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); + Preconditions.checkState( + getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE, + "Cannot reinitialize SP"); + final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( getGateKeeperService(), credentialHash, credential, userId); if (auth == null) { @@ -2689,7 +2694,7 @@ public class LockSettingsService extends ILockSettings.Stub { @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { - return true; + return getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE; } private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential, diff --git a/services/core/java/com/android/server/notification/InjectableSystemClock.java b/services/core/java/com/android/server/notification/InjectableSystemClock.java new file mode 100644 index 000000000000..4d993d19e57b --- /dev/null +++ b/services/core/java/com/android/server/notification/InjectableSystemClock.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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.notification; + +/** + * Testable wrapper around {@link android.os.SystemClock}. + * + * The default implementation at InjectableSystemClockImpl just proxies calls to the real + * SystemClock + * + * In tests, pass an instance of FakeSystemClock, which allows you to control the values returned by + * the various getters below. + */ +public interface InjectableSystemClock { + /** @see android.os.SystemClock#uptimeMillis() */ + long uptimeMillis(); + + /** @see android.os.SystemClock#elapsedRealtime() */ + long elapsedRealtime(); + + /** @see android.os.SystemClock#elapsedRealtimeNanos() */ + long elapsedRealtimeNanos(); + + /** @see android.os.SystemClock#currentThreadTimeMillis() */ + long currentThreadTimeMillis(); + + /** @see System#currentTimeMillis() */ + long currentTimeMillis(); +} + diff --git a/services/core/java/com/android/server/notification/InjectableSystemClockImpl.java b/services/core/java/com/android/server/notification/InjectableSystemClockImpl.java new file mode 100644 index 000000000000..43d756f46176 --- /dev/null +++ b/services/core/java/com/android/server/notification/InjectableSystemClockImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 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.notification; + +/** + * Default implementation of {@link InjectableSystemClock}. + * + * @hide + */ +public class InjectableSystemClockImpl implements InjectableSystemClock { + public InjectableSystemClockImpl() {} + + @Override + public long uptimeMillis() { + return android.os.SystemClock.uptimeMillis(); + } + + @Override + public long elapsedRealtime() { + return android.os.SystemClock.elapsedRealtime(); + } + + @Override + public long elapsedRealtimeNanos() { + return android.os.SystemClock.elapsedRealtimeNanos(); + } + + @Override + public long currentThreadTimeMillis() { + return android.os.SystemClock.currentThreadTimeMillis(); + } + + @Override + public long currentTimeMillis() { + return System.currentTimeMillis(); + } +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 5ddb6e1b04f6..346be75d3d3d 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -59,6 +59,7 @@ import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.media.AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; @@ -186,7 +187,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; @@ -472,6 +472,11 @@ public class NotificationManagerService extends SystemService { final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); + // Keep track of `CancelNotificationRunnable`s which have been delayed due to awaiting + // enqueued notifications to post + @GuardedBy("mNotificationLock") + final ArrayMap<NotificationRecord, ArrayList<CancelNotificationRunnable>> mDelayedCancelations = + new ArrayMap<>(); // The last key in this list owns the hardware. ArrayList<String> mLights = new ArrayList<>(); @@ -534,6 +539,7 @@ public class NotificationManagerService extends SystemService { private NotificationRecordLogger mNotificationRecordLogger; private InstanceIdSequence mNotificationInstanceIdSequence; private Set<String> mMsgPkgsAllowedAsConvos = new HashSet(); + private final InjectableSystemClock mSystemClock; static class Archive { final SparseArray<Boolean> mEnabled; @@ -747,7 +753,7 @@ public class NotificationManagerService extends SystemService { parser, mAllowedManagedServicePackages, forRestore, userId); migratedManagedServices = true; } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) { - mSnoozeHelper.readXml(parser, System.currentTimeMillis()); + mSnoozeHelper.readXml(parser, mSystemClock.currentTimeMillis()); } if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { if (forRestore && userId != UserHandle.USER_SYSTEM) { @@ -900,7 +906,7 @@ public class NotificationManagerService extends SystemService { Slog.w(TAG, "No notification with key: " + key); return; } - final long now = System.currentTimeMillis(); + final long now = mSystemClock.currentTimeMillis(); MetricsLogger.action(r.getItemLogMaker() .setType(MetricsEvent.TYPE_ACTION) .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) @@ -932,7 +938,7 @@ public class NotificationManagerService extends SystemService { Slog.w(TAG, "No notification with key: " + key); return; } - final long now = System.currentTimeMillis(); + final long now = mSystemClock.currentTimeMillis(); MetricsLogger.action(r.getLogMaker(now) .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION) .setType(MetricsEvent.TYPE_ACTION) @@ -1696,15 +1702,18 @@ public class NotificationManagerService extends SystemService { public NotificationManagerService(Context context) { this(context, new NotificationRecordLoggerImpl(), + new InjectableSystemClockImpl(), new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX)); } @VisibleForTesting public NotificationManagerService(Context context, NotificationRecordLogger notificationRecordLogger, + InjectableSystemClock systemClock, InstanceIdSequence notificationInstanceIdSequence) { super(context); mNotificationRecordLogger = notificationRecordLogger; + mSystemClock = systemClock; mNotificationInstanceIdSequence = notificationInstanceIdSequence; Notification.processAllowlistToken = ALLOWLIST_TOKEN; } @@ -2063,6 +2072,11 @@ public class NotificationManagerService extends SystemService { return getContext().getResources().getStringArray(key); } + @VisibleForTesting + protected Handler getWorkHandler() { + return mHandler; + } + @Override public void onStart() { SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { @@ -2336,7 +2350,8 @@ public class NotificationManagerService extends SystemService { mHistoryManager.onBootPhaseAppsCanStart(); registerDeviceConfigChange(); } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { - mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); + mSnoozeHelper.scheduleRepostsForPersistedNotifications( + mSystemClock.currentTimeMillis()); } } @@ -2696,7 +2711,7 @@ public class NotificationManagerService extends SystemService { .setUserId(r.getSbn().getNormalizedUserId()) .setChannelId(r.getChannel().getId()) .setChannelName(r.getChannel().getName().toString()) - .setPostedTimeMs(System.currentTimeMillis()) + .setPostedTimeMs(mSystemClock.currentTimeMillis()) .setTitle(getHistoryTitle(r.getNotification())) .setText(getHistoryText( r.getSbn().getPackageContext(getContext()), r.getNotification())) @@ -3056,6 +3071,8 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null); } + mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, + enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); try { getContext().sendBroadcastAsUser( new Intent(ACTION_APP_BLOCK_STATE_CHANGED) @@ -3517,8 +3534,9 @@ public class NotificationManagerService extends SystemService { public ParceledListSlice<ConversationChannelWrapper> getConversations( boolean onlyImportant) { enforceSystemOrSystemUI("getConversations"); + IntArray userIds = mUserProfiles.getCurrentProfileIds(); ArrayList<ConversationChannelWrapper> conversations = - mPreferencesHelper.getConversations(onlyImportant); + mPreferencesHelper.getConversations(userIds, onlyImportant); for (ConversationChannelWrapper conversation : conversations) { if (mShortcutHelper == null) { conversation.setShortcutInfo(null); @@ -5222,7 +5240,7 @@ public class NotificationManagerService extends SystemService { GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(), adjustedSbn.getInitialPid(), summaryNotification, adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY, - System.currentTimeMillis()); + mSystemClock.currentTimeMillis()); summaryRecord = new NotificationRecord(getContext(), summarySbn, notificationRecord.getChannel()); summaryRecord.setIsAppImportanceLocked( @@ -5457,6 +5475,22 @@ public class NotificationManagerService extends SystemService { mSnoozeHelper.dump(pw, filter); } + + // Log delayed notification cancels + pw.println(); + pw.println(" Delayed notification cancels:"); + if (mDelayedCancelations.isEmpty()) { + pw.println(" None"); + } else { + Set<NotificationRecord> delayedKeys = mDelayedCancelations.keySet(); + for (NotificationRecord record : delayedKeys) { + ArrayList<CancelNotificationRunnable> queuedCancels = + mDelayedCancelations.get(record); + pw.println(" (" + queuedCancels.size() + ") cancels enqueued for" + + record.getKey()); + } + } + pw.println(); } if (!zenOnly) { @@ -5675,7 +5709,7 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, notificationUid, callingPid, notification, - user, null, System.currentTimeMillis()); + user, null, mSystemClock.currentTimeMillis()); // setup local book-keeping String channelId = notification.getChannelId(); @@ -6008,7 +6042,7 @@ public class NotificationManagerService extends SystemService { final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); if (appEnqueueRate > mMaxPackageEnqueueRate) { mUsageStats.registerOverRateQuota(pkg); - final long now = SystemClock.elapsedRealtime(); + final long now = mSystemClock.elapsedRealtime(); if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate + ". Shedding " + r.getSbn().getKey() + ". package=" + pkg); @@ -6220,7 +6254,73 @@ public class NotificationManagerService extends SystemService { this.mRank = rank; this.mCount = count; this.mListener = listener; - this.mWhen = System.currentTimeMillis(); + this.mWhen = mSystemClock.currentTimeMillis(); + } + + // Move the work to this function so it can be called from PostNotificationRunnable + private void doNotificationCancelLocked() { + // Look for the notification in the posted list, since we already checked enqueued. + String listenerName = mListener == null ? null : mListener.component.toShortString(); + NotificationRecord r = + findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); + if (r != null) { + // The notification was found, check if it should be removed. + + // Ideally we'd do this in the caller of this method. However, that would + // require the caller to also find the notification. + if (mReason == REASON_CLICK) { + mUsageStats.registerClickedByUser(r); + } + + if (mReason == REASON_LISTENER_CANCEL + && (r.getNotification().flags & FLAG_BUBBLE) != 0) { + mNotificationDelegate.onBubbleNotificationSuppressionChanged( + r.getKey(), /* suppressed */ true); + return; + } + + if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { + return; + } + if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { + return; + } + + // Bubbled children get to stick around if the summary was manually cancelled + // (user removed) from systemui. + FlagChecker childrenFlagChecker = null; + if (mReason == REASON_CANCEL + || mReason == REASON_CLICK + || mReason == REASON_CANCEL_ALL) { + childrenFlagChecker = (flags) -> { + if ((flags & FLAG_BUBBLE) != 0) { + return false; + } + return true; + }; + } + + // Cancel the notification. + boolean wasPosted = removePreviousFromNotificationListsLocked(r, mWhen); + cancelNotificationLocked( + r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName); + cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, + mSendDelete, childrenFlagChecker, mReason); + updateLightsLocked(); + if (mShortcutHelper != null) { + mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, + true /* isRemoved */, + mHandler); + } + } else { + // No notification was found, assume that it is snoozed and cancel it. + if (mReason != REASON_SNOOZED) { + final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); + if (wasSnoozed) { + handleSavePolicyFile(); + } + } + } } @Override @@ -6236,91 +6336,24 @@ public class NotificationManagerService extends SystemService { // chance to post yet. List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria( mPkg, mTag, mId, mUserId); - boolean repost = false; if (enqueued.size() > 0) { - // Found something, let's see what it was - repost = true; - // If all enqueues happened before this cancel then wait for them to happen, - // otherwise we should let this cancel through so the next enqueue happens - for (NotificationRecord r : enqueued) { - if (r.mUpdateTimeMs > mWhen) { - // At least one enqueue was posted after the cancel, so we're invalid - Slog.i(TAG, "notification cancel ignored due to newer enqueued entry" - + "key=" + r.getSbn().getKey()); - return; - } + // We have found notifications that were enqueued before this cancel, but not + // yet posted. Attach this cancel to the last enqueue (the most recent), and + // we will be executed in that notification's PostNotificationRunnable + NotificationRecord enqueuedToAttach = enqueued.get(enqueued.size() - 1); + + ArrayList<CancelNotificationRunnable> delayed = + mDelayedCancelations.get(enqueuedToAttach); + if (delayed == null) { + delayed = new ArrayList<>(); } - } - if (repost) { - mHandler.post(this); + + delayed.add(this); + mDelayedCancelations.put(enqueuedToAttach, delayed); return; } - // Look for the notification in the posted list, since we already checked enqueued. - NotificationRecord r = - findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); - if (r != null) { - // The notification was found, check if it should be removed. - - // Ideally we'd do this in the caller of this method. However, that would - // require the caller to also find the notification. - if (mReason == REASON_CLICK) { - mUsageStats.registerClickedByUser(r); - } - - if (mReason == REASON_LISTENER_CANCEL - && (r.getNotification().flags & FLAG_BUBBLE) != 0) { - mNotificationDelegate.onBubbleNotificationSuppressionChanged( - r.getKey(), /* suppressed */ true); - return; - } - - if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { - return; - } - if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { - return; - } - if (r.getUpdateTimeMs() > mWhen) { - // In this case, a post must have slipped by when this runnable reposted - return; - } - - // Bubbled children get to stick around if the summary was manually cancelled - // (user removed) from systemui. - FlagChecker childrenFlagChecker = null; - if (mReason == REASON_CANCEL - || mReason == REASON_CLICK - || mReason == REASON_CANCEL_ALL) { - childrenFlagChecker = (flags) -> { - if ((flags & FLAG_BUBBLE) != 0) { - return false; - } - return true; - }; - } - - // Cancel the notification. - boolean wasPosted = removeFromNotificationListsLocked(r); - cancelNotificationLocked( - r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName); - cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName, - mSendDelete, childrenFlagChecker, mReason); - updateLightsLocked(); - if (mShortcutHelper != null) { - mShortcutHelper.maybeListenForShortcutChangesForBubbles(r, - true /* isRemoved */, - mHandler); - } - } else { - // No notification was found, assume that it is snoozed and cancel it. - if (mReason != REASON_SNOOZED) { - final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId); - if (wasSnoozed) { - handleSavePolicyFile(); - } - } - } + doNotificationCancelLocked(); } } } @@ -6343,7 +6376,7 @@ public class NotificationManagerService extends SystemService { mSnoozeHelper.getSnoozeTimeForUnpostedNotification( r.getUser().getIdentifier(), r.getSbn().getPackageName(), r.getSbn().getKey()); - final long currentTime = System.currentTimeMillis(); + final long currentTime = mSystemClock.currentTimeMillis(); if (snoozeAt.longValue() > currentTime) { (new SnoozeNotificationRunnable(r.getSbn().getKey(), snoozeAt.longValue() - currentTime, null)).snoozeLocked(r); @@ -6403,18 +6436,29 @@ public class NotificationManagerService extends SystemService { enqueueStatus); } - // tell the assistant service about the notification - if (mAssistants.isEnabled()) { - mAssistants.onNotificationEnqueuedLocked(r); - mHandler.postDelayed(new PostNotificationRunnable(r.getKey()), - DELAY_FOR_ASSISTANT_TIME); - } else { - mHandler.post(new PostNotificationRunnable(r.getKey())); - } + postPostNotificationRunnableMaybeDelayedLocked( + r, new PostNotificationRunnable(r.getKey())); } } } + /** + * Mainly needed as a hook for tests which require setting up enqueued-but-not-posted + * notification records + */ + @GuardedBy("mNotificationLock") + protected void postPostNotificationRunnableMaybeDelayedLocked( + NotificationRecord r, + PostNotificationRunnable runnable) { + // tell the assistant service about the notification + if (mAssistants.isEnabled()) { + mAssistants.onNotificationEnqueuedLocked(r); + mHandler.postDelayed(runnable, DELAY_FOR_ASSISTANT_TIME); + } else { + mHandler.post(runnable); + } + } + @GuardedBy("mNotificationLock") boolean isPackagePausedOrSuspended(String pkg, int uid) { boolean isPaused; @@ -6563,13 +6607,23 @@ public class NotificationManagerService extends SystemService { buzzBeepBlinkLoggingCode, getGroupInstanceId(n.getGroupKey())); } finally { int N = mEnqueuedNotifications.size(); + NotificationRecord enqueued = null; for (int i = 0; i < N; i++) { - final NotificationRecord enqueued = mEnqueuedNotifications.get(i); + enqueued = mEnqueuedNotifications.get(i); if (Objects.equals(key, enqueued.getKey())) { mEnqueuedNotifications.remove(i); break; } } + + // If the enqueued notification record had a cancel attached after it, execute + // it right now + if (enqueued != null && mDelayedCancelations.get(enqueued) != null) { + for (CancelNotificationRunnable r : mDelayedCancelations.get(enqueued)) { + r.doNotificationCancelLocked(); + } + mDelayedCancelations.remove(enqueued); + } } } } @@ -6798,7 +6852,8 @@ public class NotificationManagerService extends SystemService { .putExtra(EXTRA_KEY, record.getKey()), PendingIntent.FLAG_UPDATE_CURRENT); mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi); + mSystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), + pi); } } @@ -7102,8 +7157,15 @@ public class NotificationManagerService extends SystemService { // so need to check the notification still valide for vibrate. synchronized (mNotificationLock) { if (mNotificationsByKey.get(record.getKey()) != null) { + // Vibrator checks the appops for the op package, not the caller, + // so we need to add the bypass dnd flag to be heard. it's ok to + // always add this flag here because we've already checked that we can + // bypass dnd + AudioAttributes.Builder aab = + new AudioAttributes.Builder(record.getAudioAttributes()) + .setFlags(FLAG_BYPASS_INTERRUPTION_POLICY); mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getOpPkg(), - effect, "Notification (delayed)", record.getAudioAttributes()); + effect, "Notification (delayed)", aab.build()); } else { Slog.e(TAG, "No vibration for canceled notification : " + record.getKey()); @@ -7323,7 +7385,7 @@ public class NotificationManagerService extends SystemService { || visibilityChanged || interruptiveChanged; if (interceptBefore && !record.isIntercepted() - && record.isNewEnoughForAlerting(System.currentTimeMillis())) { + && record.isNewEnoughForAlerting(mSystemClock.currentTimeMillis())) { buzzBeepBlinkLocked(record); } } @@ -7610,6 +7672,34 @@ public class NotificationManagerService extends SystemService { return wasPosted; } + /** + * Similar to the above method, removes all NotificationRecords with the same key as the given + * NotificationRecord, but skips any records which are newer than the given one. + */ + private boolean removePreviousFromNotificationListsLocked(NotificationRecord r, + long removeBefore) { + // Remove notification records that occurred before the given record from both lists, + // specifically allowing newer ones to respect ordering + boolean wasPosted = false; + List<NotificationRecord> matching = + findNotificationsByListLocked(mNotificationList, r.getKey()); + for (NotificationRecord record : matching) { + // We don't need to check against update time for posted notifs + mNotificationList.remove(record); + mNotificationsByKey.remove(record.getSbn().getKey()); + wasPosted = true; + } + + matching = findNotificationsByListLocked(mEnqueuedNotifications, r.getKey()); + for (NotificationRecord record : matching) { + if (record.getUpdateTimeMs() <= removeBefore) { + mNotificationList.remove(record); + } + } + + return wasPosted; + } + @GuardedBy("mNotificationLock") private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, @NotificationListenerService.NotificationCancelReason int reason, @@ -7725,7 +7815,7 @@ public class NotificationManagerService extends SystemService { // Save it for users of getHistoricalNotifications() mArchive.record(r.getSbn(), reason); - final long now = System.currentTimeMillis(); + final long now = mSystemClock.currentTimeMillis(); final LogMaker logMaker = r.getItemLogMaker() .setType(MetricsEvent.TYPE_DISMISS) .setSubtype(reason); @@ -8281,6 +8371,21 @@ public class NotificationManagerService extends SystemService { return null; } + @GuardedBy("mNotificationLock") + private List<NotificationRecord> findNotificationsByListLocked( + ArrayList<NotificationRecord> list, + String key) { + List<NotificationRecord> matching = new ArrayList<>(); + final int n = list.size(); + for (int i = 0; i < n; i++) { + NotificationRecord r = list.get(i); + if (key.equals(r.getKey())) { + matching.add(r); + } + } + return matching; + } + /** * There may be multiple records that match your criteria. For instance if there have been * multiple notifications posted which are enqueued for the same pkg, tag, id, userId. This diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index b42fe929549a..9e91875bfd86 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -77,7 +77,6 @@ public class NotificationUsageStats { private final Map<String, AggregatedStats> mStats = new HashMap<>(); private final ArrayDeque<AggregatedStats[]> mStatsArrays = new ArrayDeque<>(); private ArraySet<String> mStatExpiredkeys = new ArraySet<>(); - private final SQLiteLog mSQLiteLog; private final Context mContext; private final Handler mHandler; private long mLastEmitTime; @@ -85,7 +84,6 @@ public class NotificationUsageStats { public NotificationUsageStats(Context context) { mContext = context; mLastEmitTime = SystemClock.elapsedRealtime(); - mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null; mHandler = new Handler(mContext.getMainLooper()) { @Override public void handleMessage(Message msg) { @@ -152,9 +150,6 @@ public class NotificationUsageStats { stats.numUndecoratedRemoteViews += (notification.hasUndecoratedRemoteView() ? 1 : 0); } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logPosted(notification); - } } /** @@ -170,9 +165,6 @@ public class NotificationUsageStats { stats.countApiUse(notification); } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logPosted(notification); - } } /** @@ -185,9 +177,6 @@ public class NotificationUsageStats { stats.numRemovedByApp++; } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logRemoved(notification); - } } /** @@ -197,9 +186,6 @@ public class NotificationUsageStats { MetricsLogger.histogram(mContext, "note_dismiss_longevity", (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000)); notification.stats.onDismiss(); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logDismissed(notification); - } } /** @@ -209,9 +195,6 @@ public class NotificationUsageStats { MetricsLogger.histogram(mContext, "note_click_longevity", (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000)); notification.stats.onClick(); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logClicked(notification); - } } public synchronized void registerPeopleAffinity(NotificationRecord notification, boolean valid, @@ -328,21 +311,18 @@ public class NotificationUsageStats { // pass } } - if (ENABLE_SQLITE_LOG) { - try { - dump.put("historical", mSQLiteLog.dumpJson(filter)); - } catch (JSONException e) { - // pass - } - } return dump; } public PulledStats remoteViewStats(long startMs, boolean aggregate) { - if (ENABLE_SQLITE_LOG) { - if (aggregate) { - return mSQLiteLog.remoteViewAggStats(startMs); + if (ENABLE_AGGREGATED_IN_MEMORY_STATS) { + PulledStats stats = new PulledStats(startMs); + for (AggregatedStats as : mStats.values()) { + if (as.numUndecoratedRemoteViews > 0) { + stats.addUndecoratedPackage(as.key, as.mCreated); + } } + return stats; } return null; } @@ -357,9 +337,6 @@ public class NotificationUsageStats { pw.println(indent + "mStatsArrays.size(): " + mStatsArrays.size()); pw.println(indent + "mStats.size(): " + mStats.size()); } - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.dump(pw, indent, filter); - } } public synchronized void emit() { @@ -1046,353 +1023,4 @@ public class NotificationUsageStats { '}'; } } - - private static class SQLiteLog { - private static final String TAG = "NotificationSQLiteLog"; - - // Message types passed to the background handler. - private static final int MSG_POST = 1; - private static final int MSG_CLICK = 2; - private static final int MSG_REMOVE = 3; - private static final int MSG_DISMISS = 4; - - private static final String DB_NAME = "notification_log.db"; - private static final int DB_VERSION = 7; - - /** Age in ms after which events are pruned from the DB. */ - private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week - /** Delay between pruning the DB. Used to throttle pruning. */ - private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L; // 6 hours - /** Mininum number of writes between pruning the DB. Used to throttle pruning. */ - private static final long PRUNE_MIN_WRITES = 1024; - - // Table 'log' - private static final String TAB_LOG = "log"; - private static final String COL_EVENT_USER_ID = "event_user_id"; - private static final String COL_EVENT_TYPE = "event_type"; - private static final String COL_EVENT_TIME = "event_time_ms"; - private static final String COL_KEY = "key"; - private static final String COL_PKG = "pkg"; - private static final String COL_NOTIFICATION_ID = "nid"; - private static final String COL_TAG = "tag"; - private static final String COL_WHEN_MS = "when_ms"; - private static final String COL_DEFAULTS = "defaults"; - private static final String COL_FLAGS = "flags"; - private static final String COL_IMPORTANCE_REQ = "importance_request"; - private static final String COL_IMPORTANCE_FINAL = "importance_final"; - private static final String COL_NOISY = "noisy"; - private static final String COL_MUTED = "muted"; - private static final String COL_DEMOTED = "demoted"; - private static final String COL_CATEGORY = "category"; - private static final String COL_ACTION_COUNT = "action_count"; - private static final String COL_POSTTIME_MS = "posttime_ms"; - private static final String COL_AIRTIME_MS = "airtime_ms"; - private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms"; - private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms"; - private static final String COL_EXPAND_COUNT = "expansion_count"; - private static final String COL_UNDECORATED = "undecorated"; - - - private static final int EVENT_TYPE_POST = 1; - private static final int EVENT_TYPE_CLICK = 2; - private static final int EVENT_TYPE_REMOVE = 3; - private static final int EVENT_TYPE_DISMISS = 4; - - private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000; - - private static long sLastPruneMs; - - private static long sNumWrites; - private final SQLiteOpenHelper mHelper; - - private final Handler mWriteHandler; - private static final long DAY_MS = 24 * 60 * 60 * 1000; - private static final String STATS_QUERY = "SELECT " + - COL_EVENT_USER_ID + ", " + - COL_PKG + ", " + - // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)' - "CAST(((%d - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " + - "AS day, " + - "COUNT(*) AS cnt, " + - "SUM(" + COL_MUTED + ") as muted, " + - "SUM(" + COL_NOISY + ") as noisy, " + - "SUM(" + COL_DEMOTED + ") as demoted, " + - "SUM(" + COL_UNDECORATED + ") as undecorated " + - "FROM " + TAB_LOG + " " + - "WHERE " + - COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + - " AND " + COL_EVENT_TIME + " > %d " + - " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG; - private static final String UNDECORATED_QUERY = "SELECT " + - COL_PKG + ", " + - "MAX(" + COL_EVENT_TIME + ") as max_time " + - "FROM " + TAB_LOG + " " + - "WHERE " + COL_UNDECORATED + "> 0 " + - " AND " + COL_EVENT_TIME + " > %d " + - "GROUP BY " + COL_PKG; - - public SQLiteLog(Context context) { - HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log", - android.os.Process.THREAD_PRIORITY_BACKGROUND); - backgroundThread.start(); - mWriteHandler = new Handler(backgroundThread.getLooper()) { - @Override - public void handleMessage(Message msg) { - NotificationRecord r = (NotificationRecord) msg.obj; - long nowMs = System.currentTimeMillis(); - switch (msg.what) { - case MSG_POST: - writeEvent(r.getSbn().getPostTime(), EVENT_TYPE_POST, r); - break; - case MSG_CLICK: - writeEvent(nowMs, EVENT_TYPE_CLICK, r); - break; - case MSG_REMOVE: - writeEvent(nowMs, EVENT_TYPE_REMOVE, r); - break; - case MSG_DISMISS: - writeEvent(nowMs, EVENT_TYPE_DISMISS, r); - break; - default: - Log.wtf(TAG, "Unknown message type: " + msg.what); - break; - } - } - }; - mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TAB_LOG + " (" + - "_id INTEGER PRIMARY KEY AUTOINCREMENT," + - COL_EVENT_USER_ID + " INT," + - COL_EVENT_TYPE + " INT," + - COL_EVENT_TIME + " INT," + - COL_KEY + " TEXT," + - COL_PKG + " TEXT," + - COL_NOTIFICATION_ID + " INT," + - COL_TAG + " TEXT," + - COL_WHEN_MS + " INT," + - COL_DEFAULTS + " INT," + - COL_FLAGS + " INT," + - COL_IMPORTANCE_REQ + " INT," + - COL_IMPORTANCE_FINAL + " INT," + - COL_NOISY + " INT," + - COL_MUTED + " INT," + - COL_DEMOTED + " INT," + - COL_CATEGORY + " TEXT," + - COL_ACTION_COUNT + " INT," + - COL_POSTTIME_MS + " INT," + - COL_AIRTIME_MS + " INT," + - COL_FIRST_EXPANSIONTIME_MS + " INT," + - COL_AIRTIME_EXPANDED_MS + " INT," + - COL_EXPAND_COUNT + " INT," + - COL_UNDECORATED + " INT" + - ")"); - } - - @Override - public void onConfigure(SQLiteDatabase db) { - // Memory optimization - close idle connections after 30s of inactivity - setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion != newVersion) { - db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG); - onCreate(db); - } - } - }; - } - - public void logPosted(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification)); - } - - public void logClicked(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification)); - } - - public void logRemoved(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification)); - } - - public void logDismissed(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification)); - } - - private JSONArray jsonPostFrequencies(DumpFilter filter) throws JSONException { - JSONArray frequencies = new JSONArray(); - SQLiteDatabase db = mHelper.getReadableDatabase(); - long midnight = getMidnightMs(); - String q = String.format(STATS_QUERY, midnight, filter.since); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - int userId = cursor.getInt(0); - String pkg = cursor.getString(1); - if (filter != null && !filter.matches(pkg)) continue; - int day = cursor.getInt(2); - int count = cursor.getInt(3); - int muted = cursor.getInt(4); - int noisy = cursor.getInt(5); - int demoted = cursor.getInt(6); - JSONObject row = new JSONObject(); - row.put("user_id", userId); - row.put("package", pkg); - row.put("day", day); - row.put("count", count); - row.put("noisy", noisy); - row.put("muted", muted); - row.put("demoted", demoted); - frequencies.put(row); - } - } finally { - cursor.close(); - } - return frequencies; - } - - public void printPostFrequencies(PrintWriter pw, String indent, DumpFilter filter) { - SQLiteDatabase db = mHelper.getReadableDatabase(); - long midnight = getMidnightMs(); - String q = String.format(STATS_QUERY, midnight, filter.since); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - int userId = cursor.getInt(0); - String pkg = cursor.getString(1); - if (filter != null && !filter.matches(pkg)) continue; - int day = cursor.getInt(2); - int count = cursor.getInt(3); - int muted = cursor.getInt(4); - int noisy = cursor.getInt(5); - int demoted = cursor.getInt(6); - pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg + - ",day=" + day + ",count=" + count + ",muted=" + muted + "/" + noisy + - ",demoted=" + demoted + "}"); - } - } finally { - cursor.close(); - } - } - - private long getMidnightMs() { - GregorianCalendar midnight = new GregorianCalendar(); - midnight.set(midnight.get(Calendar.YEAR), midnight.get(Calendar.MONTH), - midnight.get(Calendar.DATE), 23, 59, 59); - return midnight.getTimeInMillis(); - } - - private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r) { - ContentValues cv = new ContentValues(); - cv.put(COL_EVENT_USER_ID, r.getSbn().getUser().getIdentifier()); - cv.put(COL_EVENT_TIME, eventTimeMs); - cv.put(COL_EVENT_TYPE, eventType); - putNotificationIdentifiers(r, cv); - if (eventType == EVENT_TYPE_POST) { - putNotificationDetails(r, cv); - } else { - putPosttimeVisibility(r, cv); - } - cv.put(COL_UNDECORATED, (r.hasUndecoratedRemoteView() ? 1 : 0)); - SQLiteDatabase db = mHelper.getWritableDatabase(); - if (db.insert(TAB_LOG, null, cv) < 0) { - Log.wtf(TAG, "Error while trying to insert values: " + cv); - } - sNumWrites++; - pruneIfNecessary(db); - } - - private void pruneIfNecessary(SQLiteDatabase db) { - // Prune if we haven't in a while. - long nowMs = System.currentTimeMillis(); - if (sNumWrites > PRUNE_MIN_WRITES || - nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) { - sNumWrites = 0; - sLastPruneMs = nowMs; - long horizonStartMs = nowMs - HORIZON_MS; - try { - int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?", - new String[]{String.valueOf(horizonStartMs)}); - Log.d(TAG, "Pruned event entries: " + deletedRows); - } catch (SQLiteFullException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } - } - } - - private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_KEY, r.getSbn().getKey()); - outCv.put(COL_PKG, r.getSbn().getPackageName()); - } - - private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_NOTIFICATION_ID, r.getSbn().getId()); - if (r.getSbn().getTag() != null) { - outCv.put(COL_TAG, r.getSbn().getTag()); - } - outCv.put(COL_WHEN_MS, r.getSbn().getPostTime()); - outCv.put(COL_FLAGS, r.getNotification().flags); - final int before = r.stats.requestedImportance; - final int after = r.getImportance(); - final boolean noisy = r.stats.isNoisy; - outCv.put(COL_IMPORTANCE_REQ, before); - outCv.put(COL_IMPORTANCE_FINAL, after); - outCv.put(COL_DEMOTED, after < before ? 1 : 0); - outCv.put(COL_NOISY, noisy); - if (noisy && after < IMPORTANCE_HIGH) { - outCv.put(COL_MUTED, 1); - } else { - outCv.put(COL_MUTED, 0); - } - if (r.getNotification().category != null) { - outCv.put(COL_CATEGORY, r.getNotification().category); - } - outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ? - r.getNotification().actions.length : 0); - } - - private static void putPosttimeVisibility(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_POSTTIME_MS, r.stats.getCurrentPosttimeMs()); - outCv.put(COL_AIRTIME_MS, r.stats.getCurrentAirtimeMs()); - outCv.put(COL_EXPAND_COUNT, r.stats.userExpansionCount); - outCv.put(COL_AIRTIME_EXPANDED_MS, r.stats.getCurrentAirtimeExpandedMs()); - outCv.put(COL_FIRST_EXPANSIONTIME_MS, r.stats.posttimeToFirstVisibleExpansionMs); - } - - public void dump(PrintWriter pw, String indent, DumpFilter filter) { - printPostFrequencies(pw, indent, filter); - } - - public JSONObject dumpJson(DumpFilter filter) { - JSONObject dump = new JSONObject(); - try { - dump.put("post_frequency", jsonPostFrequencies(filter)); - dump.put("since", filter.since); - dump.put("now", System.currentTimeMillis()); - } catch (JSONException e) { - // pass - } - return dump; - } - - public PulledStats remoteViewAggStats(long startMs) { - PulledStats stats = new PulledStats(startMs); - SQLiteDatabase db = mHelper.getReadableDatabase(); - String q = String.format(UNDECORATED_QUERY, startMs); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - String pkg = cursor.getString(0); - long maxTimeMs = cursor.getLong(1); - stats.addUndecoratedPackage(pkg, maxTimeMs); - } - } finally { - cursor.close(); - } - return stats; - } - } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index c3cb42f95cc6..fd4a3024179c 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -51,6 +51,7 @@ import android.service.notification.RankingHelperProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.util.SparseBooleanArray; @@ -1348,36 +1349,39 @@ public class PreferencesHelper implements RankingConfig { return groups; } - public ArrayList<ConversationChannelWrapper> getConversations(boolean onlyImportant) { + public ArrayList<ConversationChannelWrapper> getConversations(IntArray userIds, + boolean onlyImportant) { synchronized (mPackagePreferences) { ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>(); - for (PackagePreferences p : mPackagePreferences.values()) { - int N = p.channels.size(); - for (int i = 0; i < N; i++) { - final NotificationChannel nc = p.channels.valueAt(i); - if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted() - && !nc.isDemoted() - && (nc.isImportantConversation() || !onlyImportant)) { - ConversationChannelWrapper conversation = new ConversationChannelWrapper(); - conversation.setPkg(p.pkg); - conversation.setUid(p.uid); - conversation.setNotificationChannel(nc); - conversation.setParentChannelLabel( - p.channels.get(nc.getParentChannelId()).getName()); - boolean blockedByGroup = false; - if (nc.getGroup() != null) { - NotificationChannelGroup group = p.groups.get(nc.getGroup()); - if (group != null) { - if (group.isBlocked()) { - blockedByGroup = true; - } else { - conversation.setGroupLabel(group.getName()); + if (userIds.binarySearch(UserHandle.getUserId(p.uid)) >= 0) { + int N = p.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = p.channels.valueAt(i); + if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted() + && !nc.isDemoted() + && (nc.isImportantConversation() || !onlyImportant)) { + ConversationChannelWrapper conversation = + new ConversationChannelWrapper(); + conversation.setPkg(p.pkg); + conversation.setUid(p.uid); + conversation.setNotificationChannel(nc); + conversation.setParentChannelLabel( + p.channels.get(nc.getParentChannelId()).getName()); + boolean blockedByGroup = false; + if (nc.getGroup() != null) { + NotificationChannelGroup group = p.groups.get(nc.getGroup()); + if (group != null) { + if (group.isBlocked()) { + blockedByGroup = true; + } else { + conversation.setGroupLabel(group.getName()); + } } } - } - if (!blockedByGroup) { - conversations.add(conversation); + if (!blockedByGroup) { + conversations.add(conversation); + } } } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 330f99523507..f8115d39b375 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -299,6 +299,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final ArraySet<File> unclaimedStages = newArraySet( stagingDir.listFiles(sStageFilter)); + // We also need to clean up orphaned staging directory for staged sessions + final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid); + unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles())); + // Ignore stages claimed by active sessions for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); @@ -393,6 +397,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements Slog.w(TAG, "Abandoning old session created at " + session.createdMillis); valid = false; + } else if (isExtraSessionForStagedInstall(session)) { + valid = false; } else { valid = true; } @@ -423,6 +429,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + // Extra sessions are created during staged install on temporary basis. They should not be + // allowed to live across system server restart. + private boolean isExtraSessionForStagedInstall(PackageInstallerSession session) { + return (session.params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0 + || (session.params.installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0; + } + @GuardedBy("mSessions") private void addHistoricalSessionLocked(PackageInstallerSession session) { CharArrayWriter writer = new CharArrayWriter(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 33193dfda69e..d690ae9e70f1 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1597,6 +1597,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { destroyInternal(); // Dispatch message to remove session from PackageInstallerService. dispatchSessionFinished(error, detailMessage, null); + // TODO(b/173194203): clean up staged session in destroyInternal() call instead + if (isStaged() && stageDir != null) { + cleanStageDir(); + } } private void onStorageUnhealthy() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0a2abff4cc5b..973d06f7ab81 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -331,6 +331,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; @@ -12450,12 +12451,17 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.addAllPermissionGroups(pkg, chatty); } + // If a permission has had its defining app changed, or it has had its protection + // upgraded, we need to revoke apps that hold it + final List<String> permissionsWithChangedDefinition; // Don't allow ephemeral applications to define new permissions. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { + permissionsWithChangedDefinition = null; Slog.w(TAG, "Permissions from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permissions."); } else { - mPermissionManager.addAllPermissions(pkg, chatty); + permissionsWithChangedDefinition = + mPermissionManager.addAllPermissions(pkg, chatty); } int collectionSize = ArrayUtils.size(pkg.getInstrumentations()); @@ -12484,7 +12490,10 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (oldPkg != null) { + boolean hasOldPkg = oldPkg != null; + boolean hasPermissionDefinitionChanges = + !CollectionUtils.isEmpty(permissionsWithChangedDefinition); + if (hasOldPkg || hasPermissionDefinitionChanges) { // We need to call revokeRuntimePermissionsIfGroupChanged async as permission // revoke callbacks from this method might need to kill apps which need the // mPackages lock on a different thread. This would dead lock. @@ -12495,9 +12504,16 @@ public class PackageManagerService extends IPackageManager.Stub // won't be granted yet, hence new packages are no problem. final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet()); - AsyncTask.execute(() -> + AsyncTask.execute(() -> { + if (hasOldPkg) { mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, - allPackageNames)); + allPackageNames); + } + if (hasPermissionDefinitionChanges) { + mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged( + permissionsWithChangedDefinition, allPackageNames); + } + }); } } @@ -18171,6 +18187,19 @@ public class PackageManagerService extends IPackageManager.Stub final String packageName = versionedPackage.getPackageName(); final long versionCode = versionedPackage.getLongVersionCode(); final String internalPackageName; + + try { + if (LocalServices.getService(ActivityTaskManagerInternal.class) + .isBaseOfLockedTask(packageName)) { + observer.onPackageDeleted( + packageName, PackageManager.DELETE_FAILED_APP_PINNED, null); + EventLog.writeEvent(0x534e4554, "127605586", -1, ""); + return; + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + synchronized (mLock) { // Normalize package name to handle renamed packages and static libs internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index ca506410e515..06b54b5c21fc 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -569,7 +569,8 @@ public class StagingManager { } } - private void resumeSession(@NonNull PackageInstallerSession session) { + private void resumeSession(@NonNull PackageInstallerSession session) + throws PackageManagerException { Slog.d(TAG, "Resuming session " + session.sessionId); final boolean hasApex = sessionContainsApex(session); @@ -634,10 +635,8 @@ public class StagingManager { if (apexSessionInfo == null) { final String errorMsg = "apexd did not know anything about a staged session " + "supposed to be activated"; - session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - errorMsg); - abortCheckpoint(session.sessionId, errorMsg); - return; + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg); } if (isApexSessionFailed(apexSessionInfo)) { String errorMsg = "APEX activation failed. Check logcat messages from apexd " @@ -646,10 +645,8 @@ public class StagingManager { errorMsg = "Session reverted due to crashing native process: " + mNativeFailureReason; } - session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - errorMsg); - abortCheckpoint(session.sessionId, errorMsg); - return; + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg); } if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) { // Apexd did not apply the session for some unknown reason. There is no @@ -657,42 +654,20 @@ public class StagingManager { // it as failed. final String errorMsg = "Staged session " + session.sessionId + "at boot " + "didn't activate nor fail. Marking it as failed anyway."; - session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - errorMsg); - abortCheckpoint(session.sessionId, errorMsg); - return; + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg); } } // Handle apk and apk-in-apex installation - try { - if (hasApex) { - checkInstallationOfApkInApexSuccessful(session); - snapshotAndRestoreForApexSession(session); - Slog.i(TAG, "APEX packages in session " + session.sessionId - + " were successfully activated. Proceeding with APK packages, if any"); - } - // The APEX part of the session is activated, proceed with the installation of APKs. - Slog.d(TAG, "Installing APK packages in session " + session.sessionId); - installApksInSession(session); - } catch (PackageManagerException e) { - session.setStagedSessionFailed(e.error, e.getMessage()); - abortCheckpoint(session.sessionId, e.getMessage()); - - // If checkpoint is not supported, we have to handle failure for one staged session. - if (!hasApex) { - return; - } - - if (!mApexManager.revertActiveSessions()) { - Slog.e(TAG, "Failed to abort APEXd session"); - } else { - Slog.e(TAG, - "Successfully aborted apexd session. Rebooting device in order to revert " - + "to the previous state of APEXd."); - mPowerManager.reboot(null); - } - return; + if (hasApex) { + checkInstallationOfApkInApexSuccessful(session); + snapshotAndRestoreForApexSession(session); + Slog.i(TAG, "APEX packages in session " + session.sessionId + + " were successfully activated. Proceeding with APK packages, if any"); } + // The APEX part of the session is activated, proceed with the installation of APKs. + Slog.d(TAG, "Installing APK packages in session " + session.sessionId); + installApksInSession(session); Slog.d(TAG, "Marking session " + session.sessionId + " as applied"); session.setStagedSessionApplied(); @@ -738,6 +713,25 @@ public class StagingManager { return ret; } + void onInstallationFailure(PackageInstallerSession session, PackageManagerException e) { + session.setStagedSessionFailed(e.error, e.getMessage()); + abortCheckpoint(session.sessionId, e.getMessage()); + + // If checkpoint is not supported, we have to handle failure for one staged session. + if (!sessionContainsApex(session)) { + return; + } + + if (!mApexManager.revertActiveSessions()) { + Slog.e(TAG, "Failed to abort APEXd session"); + } else { + Slog.e(TAG, + "Successfully aborted apexd session. Rebooting device in order to revert " + + "to the previous state of APEXd."); + mPowerManager.reboot(null); + } + } + @NonNull private PackageInstallerSession createAndWriteApkSession( @NonNull PackageInstallerSession originalSession, boolean preReboot) @@ -1088,6 +1082,26 @@ public class StagingManager { return true; } + /** + * Ensure that there is no active apex session staged in apexd for the given session. + * + * @return returns true if it is ensured that there is no active apex session, otherwise false + */ + private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) { + if (!sessionContainsApex(session)) { + return true; + } + final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId); + if (apexSession == null || isApexSessionFinalized(apexSession)) { + return true; + } + try { + return mApexManager.abortStagedSession(session.sessionId); + } catch (PackageManagerException ignore) { + return false; + } + } + private boolean isApexSessionFinalized(ApexSessionInfo session) { /* checking if the session is in a final state, i.e., not active anymore */ return session.isUnknown || session.isActivationFailed || session.isSuccess @@ -1181,7 +1195,16 @@ public class StagingManager { } else { // Session had already being marked ready. Start the checks to verify if there is any // follow-up work. - resumeSession(session); + try { + resumeSession(session); + } catch (PackageManagerException e) { + onInstallationFailure(session, e); + } catch (Exception e) { + Slog.e(TAG, "Staged install failed due to unhandled exception", e); + onInstallationFailure(session, new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Staged install failed due to unhandled exception: " + e)); + } } } @@ -1319,19 +1342,26 @@ public class StagingManager { onPreRebootVerificationComplete(sessionId); return; } - switch (msg.what) { - case MSG_PRE_REBOOT_VERIFICATION_START: - handlePreRebootVerification_Start(session); - break; - case MSG_PRE_REBOOT_VERIFICATION_APEX: - handlePreRebootVerification_Apex(session); - break; - case MSG_PRE_REBOOT_VERIFICATION_APK: - handlePreRebootVerification_Apk(session); - break; - case MSG_PRE_REBOOT_VERIFICATION_END: - handlePreRebootVerification_End(session); - break; + try { + switch (msg.what) { + case MSG_PRE_REBOOT_VERIFICATION_START: + handlePreRebootVerification_Start(session); + break; + case MSG_PRE_REBOOT_VERIFICATION_APEX: + handlePreRebootVerification_Apex(session); + break; + case MSG_PRE_REBOOT_VERIFICATION_APK: + handlePreRebootVerification_Apk(session); + break; + case MSG_PRE_REBOOT_VERIFICATION_END: + handlePreRebootVerification_End(session); + break; + } + } catch (Exception e) { + Slog.e(TAG, "Pre-reboot verification failed due to unhandled exception", e); + onPreRebootVerificationFailure(session, + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Pre-reboot verification failed due to unhandled exception: " + e); } } @@ -1368,6 +1398,17 @@ public class StagingManager { obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } + private void onPreRebootVerificationFailure(PackageInstallerSession session, + @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) { + if (!ensureActiveApexSessionIsAborted(session)) { + Slog.e(TAG, "Failed to abort apex session " + session.sessionId); + // Safe to ignore active apex session abortion failure since session will be marked + // failed on next step and staging directory for session will be deleted. + } + session.setStagedSessionFailed(errorCode, errorMessage); + onPreRebootVerificationComplete(session.sessionId); + } + // Things to do when pre-reboot verification completes for a particular sessionId private void onPreRebootVerificationComplete(int sessionId) { // Remove it from mVerificationRunning so that verification is considered complete diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index a7f30fde703b..328b02a553b1 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -727,10 +727,14 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { "compiled_trace.pb"); try { boolean exists = Files.exists(tracePath); - Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist")); + if (DEBUG) { + Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist")); + } if (exists) { long bytes = Files.size(tracePath); - Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes)); + if (DEBUG) { + Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes)); + } return bytes > 0L; } return exists; diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index cfa0449aaf33..5e04171a3bca 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -83,6 +83,8 @@ public final class BasePermission { final @PermissionType int type; + private boolean mPermissionDefinitionChanged; + String sourcePackageName; int protectionLevel; @@ -126,6 +128,11 @@ public final class BasePermission { public String getSourcePackageName() { return sourcePackageName; } + + public boolean isPermissionDefinitionChanged() { + return mPermissionDefinitionChanged; + } + public int getType() { return type; } @@ -140,6 +147,10 @@ public final class BasePermission { this.perm = perm; } + public void setPermissionDefinitionChanged(boolean shouldOverride) { + mPermissionDefinitionChanged = shouldOverride; + } + public int[] computeGids(int userId) { if (perUser) { final int[] userGids = new int[gids.length]; @@ -322,6 +333,7 @@ public final class BasePermission { final PackageSettingBase pkgSetting = (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName()); // Allow system apps to redefine non-system permissions + boolean ownerChanged = false; if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) { final boolean currentOwnerIsSystem; if (bp.perm == null) { @@ -347,6 +359,7 @@ public final class BasePermission { String msg = "New decl " + pkg + " of permission " + p.getName() + " is system; overriding " + bp.sourcePackageName; PackageManagerService.reportSettingsProblem(Log.WARN, msg); + ownerChanged = true; bp = null; } } @@ -354,6 +367,7 @@ public final class BasePermission { if (bp == null) { bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL); } + boolean wasNonRuntime = !bp.isRuntime(); StringBuilder r = null; if (bp.perm == null) { if (bp.sourcePackageName == null @@ -397,6 +411,11 @@ public final class BasePermission { && Objects.equals(bp.perm.getName(), p.getName())) { bp.protectionLevel = p.getProtectionLevel(); } + if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) { + // If this is a runtime permission and the owner has changed, or this was a normal + // permission, then permission state should be cleaned up + bp.mPermissionDefinitionChanged = true; + } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); } 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 66d8b5974261..3ffca028b1c0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2344,8 +2344,74 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void addAllPermissions(AndroidPackage pkg, boolean chatty) { + /** + * If permissions are upgraded to runtime, or their owner changes to the system, then any + * granted permissions must be revoked. + * + * @param permissionsToRevoke A list of permission names to revoke + * @param allPackageNames All package names + * @param permissionCallback Callback for permission changed + */ + private void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames, + @NonNull PermissionCallback permissionCallback) { + + final int[] userIds = mUserManagerInt.getUserIds(); + final int numPermissions = permissionsToRevoke.size(); + final int numUserIds = userIds.length; + final int numPackages = allPackageNames.size(); + final int callingUid = Binder.getCallingUid(); + + for (int permNum = 0; permNum < numPermissions; permNum++) { + String permName = permissionsToRevoke.get(permNum); + BasePermission bp = mSettings.getPermission(permName); + if (bp == null || !bp.isRuntime()) { + continue; + } + for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { + final int userId = userIds[userIdNum]; + for (int packageNum = 0; packageNum < numPackages; packageNum++) { + final String packageName = allPackageNames.get(packageNum); + final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId); + if (uid < Process.FIRST_APPLICATION_UID) { + // do not revoke from system apps + continue; + } + final int permissionState = checkPermissionImpl(permName, packageName, + userId); + final int flags = getPermissionFlags(permName, packageName, userId); + final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED + | FLAG_PERMISSION_POLICY_FIXED + | FLAG_PERMISSION_GRANTED_BY_DEFAULT + | FLAG_PERMISSION_GRANTED_BY_ROLE; + if (permissionState == PackageManager.PERMISSION_GRANTED + && (flags & flagMask) == 0) { + EventLog.writeEvent(0x534e4554, "154505240", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + EventLog.writeEvent(0x534e4554, "168319670", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + Slog.e(TAG, "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + try { + revokeRuntimePermissionInternal(permName, packageName, + false, callingUid, userId, null, permissionCallback); + } catch (Exception e) { + Slog.e(TAG, "Could not revoke " + permName + " from " + + packageName, e); + } + } + } + } + bp.setPermissionDefinitionChanged(false); + } + } + + private List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) { final int N = ArrayUtils.size(pkg.getPermissions()); + ArrayList<String> definitionChangedPermissions = new ArrayList<>(); for (int i=0; i<N; i++) { ParsedPermission p = pkg.getPermissions().get(i); @@ -2367,21 +2433,26 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + final BasePermission bp; if (p.isTree()) { - final BasePermission bp = BasePermission.createOrUpdate( + bp = BasePermission.createOrUpdate( mPackageManagerInt, mSettings.getPermissionTreeLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); mSettings.putPermissionTreeLocked(p.getName(), bp); } else { - final BasePermission bp = BasePermission.createOrUpdate( + bp = BasePermission.createOrUpdate( mPackageManagerInt, mSettings.getPermissionLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); mSettings.putPermissionLocked(p.getName(), bp); } + if (bp.isPermissionDefinitionChanged()) { + definitionChangedPermissions.add(p.getName()); + } } } + return definitionChangedPermissions; } private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { @@ -4672,9 +4743,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage, oldPackage, allPackageNames, mDefaultPermissionCallback); } + + @Override + public void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames) { + PermissionManagerService.this.revokeRuntimePermissionsIfPermissionDefinitionChanged( + permissionsToRevoke, allPackageNames, mDefaultPermissionCallback); + } + @Override - public void addAllPermissions(AndroidPackage pkg, boolean chatty) { - PermissionManagerService.this.addAllPermissions(pkg, chatty); + public List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) { + return PermissionManagerService.this.addAllPermissions(pkg, chatty); } @Override public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 37f40595450d..393e8527a991 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -254,12 +254,26 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager @NonNull ArrayList<String> allPackageNames); /** + * Some permissions might have been owned by a non-system package, and the system then defined + * said permission. Some other permissions may one have been install permissions, but are now + * runtime or higher. These permissions should be revoked. + * + * @param permissionsToRevoke A list of permission names to revoke + * @param allPackageNames All packages + */ + public abstract void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames); + + /** * Add all permissions in the given package. * <p> * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to * the permission settings. + * + * @return A list of BasePermissions that were updated, and need to be revoked from packages */ - public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); + public abstract List<String> addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty); public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 3c42e930389b..c15cbb49d695 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1466,10 +1466,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; if (mHasFeatureLeanback) { isSetupComplete &= isTvUserSetupComplete(); + } else if (mHasFeatureAuto) { + isSetupComplete &= isAutoUserSetupComplete(); } return isSetupComplete; } + private boolean isAutoUserSetupComplete() { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + "android.car.SETUP_WIZARD_IN_PROGRESS", 0, UserHandle.USER_CURRENT) == 0; + } + private boolean isTvUserSetupComplete() { return Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; @@ -2410,6 +2417,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { wm = (WindowManager) context.getSystemService(WINDOW_SERVICE); view = win.getDecorView(); + // Ignore to show splash screen if the decorView is not opaque. + if (!view.isOpaque()) { + if (DEBUG_SPLASH_SCREEN) { + Slog.d(TAG, "addSplashScreen: the view of " + packageName + + " is not opaque, cancel it"); + } + return null; + } + if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for " + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null)); diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index cc369356c1c9..9026262db897 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -127,9 +127,11 @@ public abstract class SoftRestrictedPermissionPolicy { final boolean isWhiteListed; boolean shouldApplyRestriction; final int targetSDK; + final boolean hasLegacyExternalStorage; final boolean hasRequestedLegacyExternalStorage; - final boolean shouldPreserveLegacyExternalStorage; + final boolean hasRequestedPreserveLegacyExternalStorage; final boolean hasWriteMediaStorageGrantedForUid; + final boolean isForcedScopedStorage; if (appInfo != null) { PackageManager pm = context.getPackageManager(); @@ -137,27 +139,27 @@ public abstract class SoftRestrictedPermissionPolicy { LocalServices.getService(StorageManagerInternal.class); int flags = pm.getPermissionFlags(permission, appInfo.packageName, user); isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; + hasLegacyExternalStorage = smInternal.hasLegacyExternalStorage(appInfo.uid); hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage( appInfo.uid, context); hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid( appInfo.uid, context); - shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage() - && smInternal.hasLegacyExternalStorage(appInfo.uid); + hasRequestedPreserveLegacyExternalStorage = + pkg.hasPreserveLegacyExternalStorage(); targetSDK = getMinimumTargetSDK(context, appInfo, user); - shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0 - || (targetSDK > Build.VERSION_CODES.Q - && !shouldPreserveLegacyExternalStorage) - // If the device is configured to force this app into scoped storage, - // then we should apply the restriction - || sForcedScopedStorageAppWhitelist.contains(appInfo.packageName); + shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + isForcedScopedStorage = sForcedScopedStorageAppWhitelist + .contains(appInfo.packageName); } else { isWhiteListed = false; shouldApplyRestriction = false; targetSDK = 0; + hasLegacyExternalStorage = false; hasRequestedLegacyExternalStorage = false; - shouldPreserveLegacyExternalStorage = false; + hasRequestedPreserveLegacyExternalStorage = false; hasWriteMediaStorageGrantedForUid = false; + isForcedScopedStorage = false; } // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode @@ -175,14 +177,53 @@ public abstract class SoftRestrictedPermissionPolicy { } @Override public boolean mayAllowExtraAppOp() { - return !shouldApplyRestriction - && (hasRequestedLegacyExternalStorage - || hasWriteMediaStorageGrantedForUid - || shouldPreserveLegacyExternalStorage); + // The only way to get LEGACY_STORAGE (if you didn't already have it) + // is that all of the following must be true: + // 1. The flag shouldn't be restricted + if (shouldApplyRestriction) { + return false; + } + + // 2. The app shouldn't be in sForcedScopedStorageAppWhitelist + if (isForcedScopedStorage) { + return false; + } + + // 3. The app has WRITE_MEDIA_STORAGE, OR + // the app already has legacy external storage or requested it, + // and is < R. + return hasWriteMediaStorageGrantedForUid + || ((hasLegacyExternalStorage || hasRequestedLegacyExternalStorage) + && targetSDK < Build.VERSION_CODES.R); } @Override public boolean mayDenyExtraAppOpIfGranted() { - return shouldApplyRestriction; + // If you're an app targeting < R, you can keep the app op for + // as long as you meet the conditions required to acquire it. + if (targetSDK < Build.VERSION_CODES.R) { + return !mayAllowExtraAppOp(); + } + + // For an app targeting R, the only way to lose LEGACY_STORAGE if you + // already had it is in one or more of the following conditions: + // 1. The flag became restricted + if (shouldApplyRestriction) { + return true; + } + + // The package is now a part of the forced scoped storage whitelist + if (isForcedScopedStorage) { + return true; + } + + // The package doesn't have WRITE_MEDIA_STORAGE, + // AND didn't request legacy storage to be preserved + if (!hasWriteMediaStorageGrantedForUid + && !hasRequestedPreserveLegacyExternalStorage) { + return true; + } + + return false; } }; } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 1d949dc548da..061fabf3ab2a 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -5305,6 +5305,22 @@ public final class PowerManagerService extends SystemService } @Override // Binder call + public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_DREAM_STATE, null); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_DREAM_SUPPRESSION, null); + + final long ident = Binder.clearCallingIdentity(); + try { + return isAmbientDisplayAvailable() + && mAmbientDisplaySuppressionController.isSuppressed(token, appUid); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call public boolean isAmbientDisplaySuppressed() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_DREAM_STATE, null); diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index aecf1f27da06..e09a45f9654b 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -77,8 +77,10 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; +import android.hardware.biometrics.BiometricFaceConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.face.FaceManager; +import android.hardware.face.FaceManager.GetFeatureCallback; import android.hardware.fingerprint.FingerprintManager; import android.hardware.health.V2_0.IHealth; import android.net.ConnectivityManager; @@ -247,6 +249,13 @@ public class StatsPullAtomService extends SystemService { // 20% as a conservative estimate. private static final int MAX_PROCSTATS_RAW_SHARD_SIZE = (int) (MAX_PROCSTATS_SHARD_SIZE * 1.20); + /** + * Threshold to filter out small CPU times at frequency per UID. Those small values appear + * because of more precise accounting in a BPF program. Discarding them reduces the data by at + * least 20% with negligible error. + */ + private static final int MIN_CPU_TIME_PER_UID_FREQ = 10; + private final Object mThermalLock = new Object(); @GuardedBy("mThermalLock") private IThermalService mThermalService; @@ -1554,7 +1563,7 @@ public class StatsPullAtomService extends SystemService { int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { - if (cpuFreqTimeMs[freqIndex] != 0) { + if (cpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) .writeInt(uid) @@ -3327,18 +3336,39 @@ public class StatsPullAtomService extends SystemService { try { List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); int numUsers = users.size(); + FaceManager faceManager = mContext.getSystemService(FaceManager.class); + for (int userNum = 0; userNum < numUsers; userNum++) { int userId = users.get(userNum).getUserHandle().getIdentifier(); + if (faceManager != null) { + // Store the current setting from the Face HAL, and upon next upload the value + // reported will be correct (given the user did not modify it). + faceManager.getFeature(userId, BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, + new GetFeatureCallback() { + @Override + public void onCompleted(boolean success, int feature, + boolean value) { + if (feature == FaceManager.FEATURE_REQUIRE_ATTENTION + && success) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, + value ? 1 : 0, userId); + } + } + } + ); + } + int unlockKeyguardEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId); int unlockDismissesKeyguard = Settings.Secure.getIntForUser( mContext.getContentResolver(), - Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 0, userId); + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId); int unlockAttentionRequired = Settings.Secure.getIntForUser( mContext.getContentResolver(), - Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 1, userId); + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId); int unlockAppEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId); diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index 61325cc78e74..0d11bef798ba 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -51,11 +51,15 @@ import android.app.AppGlobals; import android.app.GrantedUriPermission; import android.app.IUriGrantsManager; import android.content.ClipData; +import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.ModuleInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.PathPermission; @@ -115,13 +119,19 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { private static final String TAG = "UriGrantsManagerService"; // Maximum number of persisted Uri grants a package is allowed private static final int MAX_PERSISTED_URI_GRANTS = 512; - private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false; + private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true; + private static final String MEDIA_PROVIDER_MODULE_NAME = "com.android.mediaprovider"; + private static final long MIN_DYNAMIC_PERMISSIONS_MP_VERSION = 301400000L; private final Object mLock = new Object(); + private final Context mContext; private final H mH; ActivityManagerInternal mAmInternal; PackageManagerInternal mPmInternal; + private boolean isDynamicPermissionEnabledInMP = false; + private boolean isMPVersionChecked = false; + /** File storing persisted {@link #mGrantedUriPermissions}. */ @GuardedBy("mLock") private final AtomicFile mGrantFile; @@ -148,18 +158,19 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { private final SparseArray<ArrayMap<GrantUri, UriPermission>> mGrantedUriPermissions = new SparseArray<>(); - private UriGrantsManagerService() { - this(SystemServiceManager.ensureSystemDir()); + private UriGrantsManagerService(Context context) { + this(context, SystemServiceManager.ensureSystemDir()); } - private UriGrantsManagerService(File systemDir) { + private UriGrantsManagerService(Context context, File systemDir) { + mContext = context; mH = new H(IoThread.get().getLooper()); mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants"); } @VisibleForTesting - static UriGrantsManagerService createForTest(File systemDir) { - final UriGrantsManagerService service = new UriGrantsManagerService(systemDir); + static UriGrantsManagerService createForTest(Context context, File systemDir) { + final UriGrantsManagerService service = new UriGrantsManagerService(context, systemDir); service.mAmInternal = LocalServices.getService(ActivityManagerInternal.class); service.mPmInternal = LocalServices.getService(PackageManagerInternal.class); return service; @@ -179,7 +190,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { public Lifecycle(Context context) { super(context); - mService = new UriGrantsManagerService(); + mService = new UriGrantsManagerService(context); } @Override @@ -991,7 +1002,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { // If this provider says that grants are always required, we need to // consult it directly to determine if the UID has permission final boolean forceMet; - if (ENABLE_DYNAMIC_PERMISSIONS && pi.forceUriPermissions) { + if (ENABLE_DYNAMIC_PERMISSIONS + && pi.forceUriPermissions + && isDynamicPermissionEnabledInMP()) { final int providerUserId = UserHandle.getUserId(pi.applicationInfo.uid); final int clientUserId = UserHandle.getUserId(uid); if (providerUserId == clientUserId) { @@ -1009,6 +1022,35 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { return readMet && writeMet && forceMet; } + /** + * Returns true if the available MediaProvider version contains the changes that enable dynamic + * permission. + */ + private boolean isDynamicPermissionEnabledInMP() { + if (isMPVersionChecked) { + return isDynamicPermissionEnabledInMP; + } + + try { + ModuleInfo moduleInfo = mContext.getPackageManager().getModuleInfo( + MEDIA_PROVIDER_MODULE_NAME, PackageManager.MODULE_APEX_NAME); + PackageInfo packageInfo = + mContext.getPackageManager().getPackageInfo( + moduleInfo.getPackageName(), PackageManager.MATCH_APEX); + isDynamicPermissionEnabledInMP = + packageInfo.getLongVersionCode() >= MIN_DYNAMIC_PERMISSIONS_MP_VERSION; + } catch (NameNotFoundException e) { + Slog.i(TAG, "Module name not found: " + MEDIA_PROVIDER_MODULE_NAME); + // If module is not found, then MP changes are expected to be there (because both this + // change and the module change will be mandated together for non-module builds). + isDynamicPermissionEnabledInMP = true; + } finally { + isMPVersionChecked = true; + } + + return isDynamicPermissionEnabledInMP; + } + @GuardedBy("mLock") private void removeUriPermissionIfNeededLocked(UriPermission perm) { if (perm.modeFlags != 0) { diff --git a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java b/services/core/java/com/android/server/utils/DeviceConfigInterface.java index ab7e7f63cafd..ff609031b57c 100644 --- a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java +++ b/services/core/java/com/android/server/utils/DeviceConfigInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.wm.utils; +package com.android.server.utils; import android.annotation.NonNull; import android.annotation.Nullable; @@ -54,6 +54,11 @@ public interface DeviceConfigInterface { boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue); /** + * @see DeviceConfig#getFloat + */ + float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue); + + /** * @see DeviceConfig#addOnPropertiesChangedListener */ void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor, @@ -96,6 +101,12 @@ public interface DeviceConfigInterface { } @Override + public float getFloat(@NonNull String namespace, @NonNull String name, + float defaultValue) { + return DeviceConfig.getFloat(namespace, name, defaultValue); + } + + @Override public void addOnPropertiesChangedListener(String namespace, Executor executor, DeviceConfig.OnPropertiesChangedListener listener) { DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener); diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index ca5e38df066e..b2c1f5ba862d 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -69,6 +69,7 @@ import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallba import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -92,6 +93,9 @@ final class AccessibilityController { private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver = new SparseArray<>(); + // Set to true if initializing window population complete. + private boolean mAllObserversInitialized = true; + public boolean setMagnificationCallbacksLocked(int displayId, MagnificationCallbacks callbacks) { boolean result = false; @@ -110,7 +114,7 @@ final class AccessibilityController { } } else { final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); - if (displayMagnifier == null) { + if (displayMagnifier == null) { throw new IllegalStateException("Magnification callbacks already cleared!"); } displayMagnifier.destroyLocked(); @@ -150,8 +154,10 @@ final class AccessibilityController { "Windows for accessibility callback of display " + displayId + " already set!"); } - mWindowsForAccessibilityObserver.put(displayId, - new WindowsForAccessibilityObserver(mService, displayId, callback)); + final WindowsForAccessibilityObserver observer = + new WindowsForAccessibilityObserver(mService, displayId, callback); + mWindowsForAccessibilityObserver.put(displayId, observer); + mAllObserversInitialized &= observer.mInitialized; } else { if (isEmbeddedDisplay(dc)) { // If this display is an embedded one, its window observer should be removed along @@ -275,6 +281,41 @@ final class AccessibilityController { if (observer != null) { observer.performComputeChangedWindowsNotLocked(false); } + // Since we abandon initializing observers if no window has focus, make sure all observers + // are initialized. + sendCallbackToUninitializedObserversIfNeeded(); + } + + private void sendCallbackToUninitializedObserversIfNeeded() { + List<WindowsForAccessibilityObserver> unInitializedObservers; + synchronized (mService.mGlobalLock) { + if (mAllObserversInitialized) { + return; + } + if (mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus == null) { + return; + } + unInitializedObservers = new ArrayList<>(); + for (int i = mWindowsForAccessibilityObserver.size() - 1; i >= 0; --i) { + final WindowsForAccessibilityObserver observer = + mWindowsForAccessibilityObserver.valueAt(i); + if (!observer.mInitialized) { + unInitializedObservers.add(observer); + } + } + // Reset the flag to record the new added observer. + mAllObserversInitialized = true; + } + + boolean areAllObserversInitialized = true; + for (int i = unInitializedObservers.size() - 1; i >= 0; --i) { + final WindowsForAccessibilityObserver observer = unInitializedObservers.get(i); + observer.performComputeChangedWindowsNotLocked(true); + areAllObserversInitialized &= observer.mInitialized; + } + synchronized (mService.mGlobalLock) { + mAllObserversInitialized &= areAllObserversInitialized; + } } /** @@ -361,6 +402,8 @@ final class AccessibilityController { + "Magnification display# " + mDisplayMagnifiers.keyAt(i)); } } + pw.println(prefix + + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver); } private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver @@ -1214,6 +1257,9 @@ final class AccessibilityController { private final IntArray mEmbeddedDisplayIdList = new IntArray(0); + // Set to true if initializing window population complete. + private boolean mInitialized; + public WindowsForAccessibilityObserver(WindowManagerService windowManagerService, int displayId, WindowsForAccessibilityCallback callback) { @@ -1272,10 +1318,17 @@ final class AccessibilityController { // the window manager is still looking for where to put it. // We will do the work when we get a focus change callback. final WindowState topFocusedWindowState = getTopFocusWindow(); - if (topFocusedWindowState == null) return; + if (topFocusedWindowState == null) { + if (DEBUG) { + Slog.d(LOG_TAG, "top focused window is null, compute it again later"); + } + return; + } final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); if (dc == null) { + //It should not happen because it is created while adding the callback. + Slog.w(LOG_TAG, "display content is null, should be created later"); return; } final Display display = dc.getDisplay(); @@ -1362,6 +1415,7 @@ final class AccessibilityController { // Recycle the windows as we do not need them. clearAndRecycleWindows(windows); + mInitialized = true; } private boolean windowMattersToAccessibility(WindowState windowState, @@ -1547,6 +1601,16 @@ final class AccessibilityController { return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus; } + @Override + public String toString() { + return "WindowsForAccessibilityObserver{" + + "mDisplayId=" + mDisplayId + + ", mEmbeddedDisplayIdList=" + + Arrays.toString(mEmbeddedDisplayIdList.toArray()) + + ", mInitialized=" + mInitialized + + '}'; + } + private class MyHandler extends Handler { public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1; diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 7e6abf8b5029..8f59eef49516 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -129,7 +129,6 @@ class ActivityMetricsLogger { */ private static final int IGNORE_CALLER = -1; private static final int INVALID_DELAY = -1; - private static final int INVALID_TRANSITION_TYPE = -1; // Preallocated strings we are sending to tron, so we don't have to allocate a new one every // time we log. @@ -224,22 +223,19 @@ class ActivityMetricsLogger { static TransitionInfo create(@NonNull ActivityRecord r, @NonNull LaunchingState launchingState, boolean processRunning, boolean processSwitch, int startResult) { - int transitionType = INVALID_TRANSITION_TYPE; + if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) { + return null; + } + final int transitionType; if (processRunning) { - if (startResult == START_SUCCESS) { - transitionType = TYPE_TRANSITION_WARM_LAUNCH; - } else if (startResult == START_TASK_TO_FRONT) { - transitionType = TYPE_TRANSITION_HOT_LAUNCH; - } - } else if (startResult == START_SUCCESS || startResult == START_TASK_TO_FRONT) { + transitionType = r.attachedToProcess() + ? TYPE_TRANSITION_HOT_LAUNCH + : TYPE_TRANSITION_WARM_LAUNCH; + } else { // Task may still exist when cold launching an activity and the start result will be // set to START_TASK_TO_FRONT. Treat this as a COLD launch. transitionType = TYPE_TRANSITION_COLD_LAUNCH; } - if (transitionType == INVALID_TRANSITION_TYPE) { - // That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT. - return null; - } return new TransitionInfo(r, launchingState, transitionType, processRunning, processSwitch); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index d4dd35f53cf0..eb749f6e06bb 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -568,4 +568,10 @@ public abstract class ActivityTaskManagerInternal { /** Set all associated companion app that belongs to an userId. */ public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages); + + /** + * @param packageName The package to check + * @return Whether the package is the base of any locked task + */ + public abstract boolean isBaseOfLockedTask(String packageName); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0542ef9b09a4..8dbd661cff91 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -7473,5 +7473,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mCompanionAppUidsMap.put(userId, result); } } + + + @Override + public boolean isBaseOfLockedTask(String packageName) { + synchronized (mGlobalLock) { + return getLockTaskController().isBaseOfLockedTask(packageName); + } + } } } diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 2be3acc52058..fa2a42e72054 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -200,6 +200,9 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { Comparator.comparingInt(WindowToken::getWindowLayerFromType); private final Predicate<WindowState> mGetOrientingWindow = w -> { + if (!w.isVisible() || !w.mLegacyPolicyVisibilityAfterAnim) { + return false; + } final WindowManagerPolicy policy = mWmService.mPolicy; if (policy.isKeyguardHostWindow(w.mAttrs)) { if (mWmService.mKeyguardGoingAway) { @@ -235,6 +238,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { @Override int getOrientation(int candidate) { + mLastOrientationSource = null; // Find a window requesting orientation. final WindowState win = getWindow(mGetOrientingWindow); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e36b84fb37c4..fa6baa1d9225 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -188,6 +188,8 @@ import android.view.IWindow; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputWindowHandle; +import android.view.InsetsSource; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.MagnificationSpec; import android.view.RemoteAnimationDefinition; @@ -1666,6 +1668,28 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) { + if (mFixedRotationLaunchingApp != null) { + // The insets state of fixed rotation app is a rotated copy. Make sure the visibilities + // of insets sources are consistent with the latest state. + final InsetsState rotatedState = + mFixedRotationLaunchingApp.getFixedRotationTransformInsetsState(); + if (rotatedState != null) { + final InsetsState state = mInsetsStateController.getRawInsetsState(); + for (int i = 0; i < InsetsState.SIZE; i++) { + final InsetsSource source = state.peekSource(i); + if (source != null) { + rotatedState.setSourceVisible(i, source.isVisible()); + } + } + } + } + forAllWindows(dispatchInsetsChanged, true /* traverseTopToBottom */); + if (mRemoteInsetsControlTarget != null) { + mRemoteInsetsControlTarget.notifyInsetsChanged(); + } + } + /** * Update rotation of the display. * @@ -5703,7 +5727,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } - if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) { + if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp + && animatingRecents.isVisible()) { // The recents activity should be going to be invisible (switch to another app or // return to original top). Only clear the top launching record without finishing // the transform immediately because it won't affect display orientation. And before diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 515d1f58d3ef..29881cc761b2 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -549,11 +549,10 @@ public class DisplayPolicy { synchronized (mLock) { mDisplayContent.calculateSystemGestureExclusion( excludedRegion, null /* outUnrestricted */); - final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture - || mNavigationBarPosition == NAV_BAR_RIGHT; - if (mNavigationBar != null && sideAllowed - && !mSystemGestures.currentGestureStartedInRegion( - excludedRegion)) { + final boolean excluded = + mSystemGestures.currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { requestTransientBars(mNavigationBar); } checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); @@ -567,11 +566,10 @@ public class DisplayPolicy { synchronized (mLock) { mDisplayContent.calculateSystemGestureExclusion( excludedRegion, null /* outUnrestricted */); - final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture - || mNavigationBarPosition == NAV_BAR_LEFT; - if (mNavigationBar != null && sideAllowed - && !mSystemGestures.currentGestureStartedInRegion( - excludedRegion)) { + final boolean excluded = + mSystemGestures.currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { requestTransientBars(mNavigationBar); } checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); @@ -3437,17 +3435,16 @@ public class DisplayPolicy { } final InsetsState requestedState = controlTarget.getRequestedInsetsState(); + final InsetsSource nbSource = requestedState.peekSource(ITYPE_NAVIGATION_BAR); + final InsetsSource sbSource = requestedState.peekSource(ITYPE_STATUS_BAR); + final InsetsSource enbSource = requestedState.peekSource(ITYPE_EXTRA_NAVIGATION_BAR); + final InsetsSource cbSource = requestedState.peekSource(ITYPE_CLIMATE_BAR); final @InsetsType int restorePositionTypes = - (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR) + (nbSource != null && nbSource.isVisible() ? Type.navigationBars() : 0) + | (sbSource != null && sbSource.isVisible() ? Type.statusBars() : 0) + | (mExtraNavBarAlt != null && enbSource != null && enbSource.isVisible() ? Type.navigationBars() : 0) - | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) - ? Type.statusBars() : 0) - | (mExtraNavBarAlt != null - && requestedState.getSourceOrDefaultVisibility( - ITYPE_EXTRA_NAVIGATION_BAR) - ? Type.navigationBars() : 0) - | (mClimateBarAlt != null - && requestedState.getSourceOrDefaultVisibility(ITYPE_CLIMATE_BAR) + | (mClimateBarAlt != null && cbSource != null && cbSource.isVisible() ? Type.statusBars() : 0); if (swipeTarget == mNavigationBar diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java index aac6b2544c4f..e925b054a92b 100644 --- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java +++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java @@ -27,7 +27,7 @@ import android.util.ArraySet; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; -import com.android.server.wm.utils.DeviceConfigInterface; +import com.android.server.utils.DeviceConfigInterface; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index fd67db1d5cc9..be1d0fc0ecc8 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -36,6 +36,7 @@ import android.view.InsetsAnimationControlCallbacks; import android.view.InsetsAnimationControlImpl; import android.view.InsetsAnimationControlRunner; import android.view.InsetsController; +import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; @@ -212,11 +213,21 @@ class InsetsPolicy { * @see InsetsStateController#getInsetsForDispatch */ InsetsState getInsetsForDispatch(WindowState target) { - InsetsState originalState = mStateController.getInsetsForDispatch(target); + final InsetsState originalState = mStateController.getInsetsForDispatch(target); InsetsState state = originalState; for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { - state = new InsetsState(state); - state.setSourceVisible(mShowingTransientTypes.get(i), false); + final int type = mShowingTransientTypes.get(i); + final InsetsSource originalSource = state.peekSource(type); + if (originalSource != null && originalSource.isVisible()) { + if (state == originalState) { + // The source will be modified, create a non-deep copy to store the new one. + state = new InsetsState(originalState); + } + // Replace the source with a copy in invisible state. + final InsetsSource source = new InsetsSource(originalSource); + source.setVisible(false); + state.addSource(source); + } } return state; } @@ -252,11 +263,14 @@ class InsetsPolicy { } } + /** + * If the caller is not {@link #updateBarControlTarget}, it should call + * updateBarControlTarget(mFocusedWin) after this invocation. + */ private void abortTransient() { mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray()); mShowingTransientTypes.clear(); - updateBarControlTarget(mFocusedWin); } private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused, @@ -290,7 +304,7 @@ class InsetsPolicy { // fake control to the client, so that it can re-show the bar during this scenario. return mDummyControlTarget; } - if (mPolicy.topAppHidesStatusBar()) { + if (!canBeTopFullscreenOpaqueWindow(focusedWin) && mPolicy.topAppHidesStatusBar()) { // Non-fullscreen focused window should not break the state that the top-fullscreen-app // window hides status bar. return mPolicy.getTopFullscreenOpaqueWindow(); @@ -298,6 +312,16 @@ class InsetsPolicy { return focusedWin; } + private static boolean canBeTopFullscreenOpaqueWindow(@Nullable WindowState win) { + // The condition doesn't use WindowState#canAffectSystemUiFlags because the window may + // haven't drawn or committed the visibility. + final boolean nonAttachedAppWindow = win != null + && win.mAttrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && win.mAttrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + return nonAttachedAppWindow && win.mAttrs.isFullscreen() && !win.isFullyTransparent() + && !win.inMultiWindowMode(); + } + private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode) { if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) { diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 68405c40ce37..c56457a0e5da 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -107,6 +107,10 @@ class InsetsStateController { * @return The state stripped of the necessary information. */ InsetsState getInsetsForDispatch(@NonNull WindowState target) { + final InsetsState rotatedState = target.mToken.getFixedRotationTransformInsetsState(); + if (rotatedState != null) { + return rotatedState; + } final InsetsSourceProvider provider = target.getControllableInsetProvider(); final @InternalInsetsType int type = provider != null ? provider.getSource().getType() : ITYPE_INVALID; @@ -473,10 +477,7 @@ class InsetsStateController { } void notifyInsetsChanged() { - mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */); - if (mDisplayContent.mRemoteInsetsControlTarget != null) { - mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged(); - } + mDisplayContent.notifyInsetsChanged(mDispatchInsetsChanged); } void dump(String prefix, PrintWriter pw) { diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index c36dede013f4..c4a42ab7e7be 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -871,6 +871,21 @@ public class LockTaskController { } /** + * @param packageName The package to check + * @return Whether the package is the base of any locked task + */ + boolean isBaseOfLockedTask(String packageName) { + for (int i = 0; i < mLockTaskModeTasks.size(); i++) { + final Intent bi = mLockTaskModeTasks.get(i).getBaseIntent(); + if (bi != null && packageName.equals(bi.getComponent() + .getPackageName())) { + return true; + } + } + return false; + } + + /** * Gets the cached value of LockTask feature flags for a specific user. */ private int getLockTaskFeaturesForUser(int userId) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0d55dece34a9..eaf76938e2e8 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -994,9 +994,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - // Remove all deferred displays stacks, tasks, and activities. - handleCompleteDeferredRemoval(); - forAllDisplays(dc -> { dc.getInputMonitor().updateInputWindowsLw(true /*force*/); dc.updateSystemGestureExclusion(); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index e85049cad2f4..3c0cb17af603 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -480,9 +480,7 @@ class TaskSnapshotController { final int color = ColorUtils.setAlphaComponent( task.getTaskDescription().getBackgroundColor(), 255); final LayoutParams attrs = mainWindow.getAttrs(); - final InsetsPolicy insetsPolicy = mainWindow.getDisplayContent().getInsetsPolicy(); - final InsetsState insetsState = - new InsetsState(insetsPolicy.getInsetsForDispatch(mainWindow)); + final InsetsState insetsState = new InsetsState(mainWindow.getInsetsState()); mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState()); final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrameLw(), insetsState); final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 6cc0ba5e209c..94229b94eb64 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -245,11 +245,7 @@ class TaskSnapshotSurface implements StartingSurface { task.getBounds(taskBounds); currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation; activityType = activity.getActivityType(); - - final InsetsPolicy insetsPolicy = topFullscreenOpaqueWindow.getDisplayContent() - .getInsetsPolicy(); - insetsState = - new InsetsState(insetsPolicy.getInsetsForDispatch(topFullscreenOpaqueWindow)); + insetsState = new InsetsState(topFullscreenOpaqueWindow.getInsetsState()); mergeInsetsSources(insetsState, topFullscreenOpaqueWindow.getRequestedInsetsState()); } try { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 9d0bac9dd290..9d07304aa2b9 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -143,6 +143,9 @@ public class WindowAnimator { ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate"); mService.openSurfaceTransaction(); try { + // Remove all deferred displays, tasks, and activities. + mService.mRoot.handleCompleteDeferredRemoval(); + final AccessibilityController accessibilityController = mService.mAccessibilityController; final int numDisplays = mDisplayContentsAnimators.size(); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0ade5867d059..6cd6a57eedd4 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1060,7 +1060,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // descendant. E.g. if a display is pending to be removed because it contains an // activity with {@link ActivityRecord#mIsExiting} is true, the display may be // removed when completing the removal of the last activity from - // {@link ActivityRecord#checkCompleteDeferredRemoval}. + // {@link ActivityRecord#handleCompleteDeferredRemoval}. return false; } } @@ -2555,8 +2555,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< pw.print(prefix); pw.println("ContainerAnimator:"); mSurfaceAnimator.dump(pw, prefix + " "); } - if (mLastOrientationSource != null) { + if (mLastOrientationSource != null && this == mDisplayContent) { pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource); + pw.println(prefix + "deepestLastOrientationSource=" + getLastOrientationSource()); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java index b0c5dbc6cca3..a5ebf9ac74b9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerConstants.java +++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java @@ -23,7 +23,7 @@ import android.provider.AndroidDeviceConfig; import android.provider.DeviceConfig; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.wm.utils.DeviceConfigInterface; +import com.android.server.utils.DeviceConfigInterface; import java.io.PrintWriter; import java.util.Objects; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b7a2eb3c705d..d9594a40bde3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -282,8 +282,8 @@ import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; import com.android.server.protolog.ProtoLogImpl; import com.android.server.protolog.common.ProtoLog; +import com.android.server.utils.DeviceConfigInterface; import com.android.server.utils.PriorityDump; -import com.android.server.wm.utils.DeviceConfigInterface; import java.io.BufferedWriter; import java.io.DataInputStream; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f9b5e0e70588..2329a6082f33 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1526,11 +1526,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return getDisplayContent().getDisplayInfo(); } + /** + * Returns the insets state for the client. Its sources may be the copies with visibility + * modification according to the state of transient bars. + */ InsetsState getInsetsState() { - final InsetsState insetsState = mToken.getFixedRotationTransformInsetsState(); - if (insetsState != null) { - return insetsState; - } return getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index faf3f06a3035..bf10526aeec2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -641,6 +641,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final boolean mIsWatch; /** + * Whether or not this device is an automotive. + */ + private final boolean mIsAutomotive; + + /** * Whether this device has the telephony feature. */ final boolean mHasTelephonyFeature; @@ -2567,6 +2572,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .hasSystemFeature(PackageManager.FEATURE_WATCH); mHasTelephonyFeature = mInjector.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TELEPHONY); + mIsAutomotive = mInjector.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); mBackgroundHandler = BackgroundThread.getHandler(); // Needed when mHasFeature == false, because it controls the certificate warning text. @@ -6080,9 +6087,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Require authentication for the device or profile if (userToLock == UserHandle.USER_ALL) { - // Power off the display - mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); + if (mIsAutomotive) { + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "lockNow(): not powering off display on automotive" + + " build"); + } + } else { + // Power off the display + mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); + } mInjector.getIWindowManager().lockNow(null); } else { mInjector.getTrustManager().setDeviceLockedForUser(userToLock, true); diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 979f4e179e95..e57097e48881 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -48,7 +48,6 @@ android_test { // TODO: remove once Android migrates to JUnit 4.12, // which provides assertThrows "testng", - ], aidl: { @@ -110,6 +109,7 @@ java_library { "utils/**/*.java", "utils/**/*.kt", "utils-mockito/**/*.kt", + ":services.core-sources-deviceconfig-interface", ], static_libs: [ "junit", @@ -126,6 +126,7 @@ java_library { "utils/**/*.java", "utils/**/*.kt", "utils-mockito/**/*.kt", + ":services.core-sources-deviceconfig-interface", ], static_libs: [ "junit", diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 6db3233b0266..36cfcc6c2e83 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -77,6 +77,7 @@ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> <uses-permission android:name="android.permission.DUMP"/> <uses-permission android:name="android.permission.READ_DREAM_STATE"/> + <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION"/> <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/> diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java index 538e2d51e88f..0e787853f617 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java @@ -26,6 +26,7 @@ import android.accessibilityservice.AccessibilityService; import android.content.Context; import android.graphics.Point; import android.graphics.PointF; +import android.os.Handler; import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; @@ -56,7 +57,8 @@ public class GestureManifoldTest { // Construct a testable GestureManifold. mResultListener = mock(GestureManifold.Listener.class); mState = new TouchState(); - mManifold = new GestureManifold(context, mResultListener, mState); + Handler handler = new Handler(context.getMainLooper()); + mManifold = new GestureManifold(context, mResultListener, mState, handler); // Play the role of touch explorer in updating the shared state. when(mResultListener.onGestureStarted()).thenReturn(onGestureStarted()); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 9053234aa220..13587bc70b24 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -16,6 +16,8 @@ package com.android.server.accessibility.gestures; +import static android.view.ViewConfiguration.getDoubleTapTimeout; + import static com.android.server.accessibility.gestures.TouchState.STATE_CLEAR; import static com.android.server.accessibility.gestures.TouchState.STATE_DELEGATING; import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING; @@ -23,6 +25,7 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_E import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import android.content.Context; @@ -31,6 +34,7 @@ import android.os.SystemClock; import android.testing.DexmakerShareClassLoaderRule; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.ViewConfiguration; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -52,6 +56,8 @@ import java.util.List; public class TouchExplorerTest { private static final String LOG_TAG = "TouchExplorerTest"; + // The constant of mDetermineUserIntentTimeout. + private static final int USER_INTENT_TIMEOUT = getDoubleTapTimeout(); private static final int FLAG_1FINGER = 0x8000; private static final int FLAG_2FINGERS = 0x0100; private static final int FLAG_3FINGERS = 0x0200; @@ -72,6 +78,8 @@ public class TouchExplorerTest { private EventStreamTransformation mCaptor; private MotionEvent mLastEvent; private TouchExplorer mTouchExplorer; + private Context mContext; + private int mTouchSlop; private long mLastDownTime = Integer.MIN_VALUE; // mock package-private GestureManifold class @@ -91,7 +99,9 @@ public class TouchExplorerTest { public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mEvents.add(0, event.copy()); // LastEvent may not match if we're clearing the state - if (mLastEvent != null) { + // The last event becomes ACTION_UP event when sending the ACTION_CANCEL event, + // so ignoring the ACTION_CANCEL event checking. + if (mLastEvent != null && rawEvent.getActionMasked() != MotionEvent.ACTION_CANCEL) { MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent); assertThat(rawEvent, lastEventMatcher); } @@ -109,14 +119,52 @@ public class TouchExplorerTest { @Before public void setUp() { - Context context = InstrumentationRegistry.getContext(); - AccessibilityManagerService ams = new AccessibilityManagerService(context); + mContext = InstrumentationRegistry.getContext(); + mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + AccessibilityManagerService ams = new AccessibilityManagerService(mContext); GestureManifold detector = mock(GestureManifold.class); mCaptor = new EventCaptor(); - mTouchExplorer = new TouchExplorer(context, ams, detector); + mTouchExplorer = new TouchExplorer(mContext, ams, detector); mTouchExplorer.setNext(mCaptor); } + /** + * Test the case where the event location is correct when clicking after the following + * situation happened: entering the delegate state through doubleTapAndHold gesture and + * receiving a cancel event to return the clear state. + */ + @Test + public void testClick_afterCanceledDoubleTapAndHold_eventLocationIsCorrect() + throws InterruptedException { + // Generates the click position by this click operation, otherwise the offset used + // while delegating could not be set. + send(downEvent(DEFAULT_X + 10, DEFAULT_Y + 10)); + // Waits for transition to touch exploring state. + Thread.sleep(2 * USER_INTENT_TIMEOUT); + send(upEvent()); + + // Simulates detecting the doubleTapAndHold gesture and enters the delegate state. + final MotionEvent sendEvent = + fromTouchscreen(downEvent(DEFAULT_X + 100, DEFAULT_Y + 100)); + mTouchExplorer.onDoubleTapAndHold(sendEvent, sendEvent, 0); + assertState(STATE_DELEGATING); + + send(cancelEvent()); + + // Generates the click operation, and checks the event location of the ACTION_HOVER_ENTER + // event is correct. + send(downEvent()); + // Waits for transition to touch exploring state. + Thread.sleep(2 * USER_INTENT_TIMEOUT); + send(upEvent()); + + final List<MotionEvent> events = getCapturedEvents(); + assertTrue(events.stream().anyMatch( + motionEvent -> motionEvent.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER + && motionEvent.getX() == DEFAULT_X + && motionEvent.getY() == DEFAULT_Y)); + } + @Test public void testTwoFingersMove_shouldDelegatingAndInjectActionDownPointerDown() { goFromStateClearTo(STATE_MOVING_2FINGERS); @@ -158,7 +206,7 @@ public class TouchExplorerTest { goFromStateClearTo(STATE_DRAGGING_2FINGERS); assertState(STATE_DRAGGING); - assertCapturedEvents(MotionEvent.ACTION_DOWN); + assertCapturedEvents(MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE); assertCapturedEventsNoHistory(); } @@ -170,6 +218,7 @@ public class TouchExplorerTest { assertState(STATE_DELEGATING); assertCapturedEvents( /* goto dragging state */ MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_MOVE, /* leave dragging state */ MotionEvent.ACTION_UP, MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN); @@ -226,13 +275,13 @@ public class TouchExplorerTest { break; case STATE_DRAGGING_2FINGERS: { goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER); - moveEachPointers(mLastEvent, p(10, 0), p(10, 0)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(mTouchSlop, 0)); send(mLastEvent); } break; case STATE_PINCH_2FINGERS: { goFromStateClearTo(STATE_DRAGGING_2FINGERS); - moveEachPointers(mLastEvent, p(10, 0), p(-10, 1)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(-mTouchSlop, 1)); send(mLastEvent); } break; @@ -289,6 +338,19 @@ public class TouchExplorerTest { return ((EventCaptor) mCaptor).mEvents; } + private MotionEvent cancelEvent() { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain(mLastDownTime, mLastDownTime, MotionEvent.ACTION_CANCEL, + DEFAULT_X, DEFAULT_Y, 0)); + } + + private MotionEvent downEvent(float x, float y) { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain(mLastDownTime, mLastDownTime, MotionEvent.ACTION_DOWN, x, y, 0)); + } + private MotionEvent downEvent() { mLastDownTime = SystemClock.uptimeMillis(); return fromTouchscreen( diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 43a396d8e5d7..c467ee949aeb 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -16,49 +16,99 @@ package com.android.server.display; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; + +import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER; + +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.annotation.NonNull; +import android.content.ContentResolver; import android.content.Context; +import android.content.ContextWrapper; +import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.os.Handler; import android.os.Looper; +import android.provider.DeviceConfig; +import android.provider.Settings; +import android.test.mock.MockContentResolver; +import android.util.Slog; import android.util.SparseArray; import android.view.Display; -import androidx.test.InstrumentationRegistry; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.Preconditions; +import com.android.internal.util.test.FakeSettingsProvider; +import com.android.internal.util.test.FakeSettingsProviderRule; import com.android.server.display.DisplayModeDirector.BrightnessObserver; import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs; import com.android.server.display.DisplayModeDirector.Vote; +import com.android.server.testutils.FakeDeviceConfigInterface; import com.google.common.truth.Truth; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + @SmallTest @RunWith(AndroidJUnit4.class) public class DisplayModeDirectorTest { // The tolerance within which we consider something approximately equals. + private static final String TAG = "DisplayModeDirectorTest"; + private static final boolean DEBUG = false; private static final float FLOAT_TOLERANCE = 0.01f; private Context mContext; + private FakesInjector mInjector; + private Handler mHandler; + @Rule + public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); + when(mContext.getContentResolver()).thenReturn(resolver); + mInjector = new FakesInjector(); + mHandler = new Handler(Looper.getMainLooper()); } private DisplayModeDirector createDirectorFromRefreshRateArray( float[] refreshRates, int baseModeId) { DisplayModeDirector director = - new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper())); + new DisplayModeDirector(mContext, mHandler, mInjector); int displayId = 0; Display.Mode[] modes = new Display.Mode[refreshRates.length]; for (int i = 0; i < refreshRates.length; i++) { @@ -159,9 +209,9 @@ public class DisplayModeDirectorTest { } @Test - public void testBrightnessHasLowerPriorityThanUser() { - assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE); - assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE); + public void testFlickerHasLowerPriorityThanUser() { + assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE); + assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE); int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(60, 90); @@ -169,7 +219,7 @@ public class DisplayModeDirectorTest { SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); votesByDisplay.put(displayId, votes); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); - votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60)); + votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); @@ -177,7 +227,7 @@ public class DisplayModeDirectorTest { votes.clear(); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); - votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90)); + votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90)); director.injectVotesByDisplay(votesByDisplay); desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); @@ -185,7 +235,7 @@ public class DisplayModeDirectorTest { votes.clear(); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90)); - votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60)); + votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); @@ -193,7 +243,7 @@ public class DisplayModeDirectorTest { votes.clear(); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60)); - votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90)); + votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90)); director.injectVotesByDisplay(votesByDisplay); desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); @@ -202,10 +252,10 @@ public class DisplayModeDirectorTest { @Test public void testAppRequestRefreshRateRange() { - // Confirm that the app request range doesn't include low brightness or min refresh rate - // settings, but does include everything else. + // Confirm that the app request range doesn't include flicker or min refresh rate settings, + // but does include everything else. assertTrue( - Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF); + PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF); assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF); assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE @@ -216,7 +266,7 @@ public class DisplayModeDirectorTest { SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); votesByDisplay.put(displayId, votes); - votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60)); + votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); @@ -302,4 +352,343 @@ public class DisplayModeDirectorTest { verifyBrightnessObserverCall(director, 90, 90, 0, 90, 90); verifyBrightnessObserverCall(director, 120, 90, 0, 120, 90); } + + @Test + public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0); + SensorManager sensorManager = createMockSensorManager(createLightSensor()); + + final int initialRefreshRate = 60; + mInjector.getDeviceConfig().setRefreshRateInLowZone(initialRefreshRate); + director.start(sensorManager); + assertThat(director.getBrightnessObserver().getRefreshRateInLowZone()) + .isEqualTo(initialRefreshRate); + + final int updatedRefreshRate = 90; + mInjector.getDeviceConfig().setRefreshRateInLowZone(updatedRefreshRate); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getBrightnessObserver().getRefreshRateInLowZone()) + .isEqualTo(updatedRefreshRate); + } + + @Test + public void testBrightnessObserverThresholdsInZone() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0); + SensorManager sensorManager = createMockSensorManager(createLightSensor()); + + final int[] initialDisplayThresholds = { 10 }; + final int[] initialAmbientThresholds = { 20 }; + + final FakeDeviceConfig config = mInjector.getDeviceConfig(); + config.setLowDisplayBrightnessThresholds(initialDisplayThresholds); + config.setLowAmbientBrightnessThresholds(initialAmbientThresholds); + director.start(sensorManager); + + assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds()) + .isEqualTo(initialDisplayThresholds); + assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds()) + .isEqualTo(initialAmbientThresholds); + + final int[] updatedDisplayThresholds = { 9, 14 }; + final int[] updatedAmbientThresholds = { -1, 19 }; + config.setLowDisplayBrightnessThresholds(updatedDisplayThresholds); + config.setLowAmbientBrightnessThresholds(updatedAmbientThresholds); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds()) + .isEqualTo(updatedDisplayThresholds); + assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds()) + .isEqualTo(updatedAmbientThresholds); + } + + @Test + public void testLockFpsForLowZone() throws Exception { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + setPeakRefreshRate(90); + director.getSettingsObserver().setDefaultRefreshRate(90); + director.getBrightnessObserver().setDefaultDisplayState(true); + + final FakeDeviceConfig config = mInjector.getDeviceConfig(); + config.setRefreshRateInLowZone(90); + config.setLowDisplayBrightnessThresholds(new int[] { 10 }); + config.setLowAmbientBrightnessThresholds(new int[] { 20 }); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + + director.start(sensorManager); + + ArgumentCaptor<SensorEventListener> listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) + .registerListener( + listenerCaptor.capture(), + eq(lightSensor), + anyInt(), + any(Handler.class)); + SensorEventListener listener = listenerCaptor.getValue(); + + setBrightness(10); + // Sensor reads 20 lux, + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/)); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER); + assertVoteForRefreshRateLocked(vote, 90 /*fps*/); + + setBrightness(125); + // Sensor reads 1000 lux, + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/)); + + vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER); + assertThat(vote).isNull(); + } + + @Test + public void testLockFpsForHighZone() throws Exception { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + setPeakRefreshRate(90 /*fps*/); + director.getSettingsObserver().setDefaultRefreshRate(90); + director.getBrightnessObserver().setDefaultDisplayState(true); + + final FakeDeviceConfig config = mInjector.getDeviceConfig(); + config.setRefreshRateInHighZone(60); + config.setHighDisplayBrightnessThresholds(new int[] { 255 }); + config.setHighAmbientBrightnessThresholds(new int[] { 8000 }); + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + + director.start(sensorManager); + + ArgumentCaptor<SensorEventListener> listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1))) + .registerListener( + listenerCaptor.capture(), + eq(lightSensor), + anyInt(), + any(Handler.class)); + SensorEventListener listener = listenerCaptor.getValue(); + + setBrightness(100); + // Sensor reads 2000 lux, + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000)); + + Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER); + assertThat(vote).isNull(); + + setBrightness(255); + // Sensor reads 9000 lux, + listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000)); + + vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER); + assertVoteForRefreshRateLocked(vote, 60 /*fps*/); + } + + private void assertVoteForRefreshRateLocked(Vote vote, float refreshRate) { + assertThat(vote).isNotNull(); + final DisplayModeDirector.RefreshRateRange expectedRange = + new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate); + assertThat(vote.refreshRateRange).isEqualTo(expectedRange); + } + + private static class FakeDeviceConfig extends FakeDeviceConfigInterface { + @Override + public String getProperty(String namespace, String name) { + Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)); + return super.getProperty(namespace, name); + } + + @Override + public void addOnPropertiesChangedListener( + String namespace, + Executor executor, + DeviceConfig.OnPropertiesChangedListener listener) { + Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)); + super.addOnPropertiesChangedListener(namespace, executor, listener); + } + + void setRefreshRateInLowZone(int fps) { + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE, + String.valueOf(fps)); + } + + void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) { + String thresholds = toPropertyValue(brightnessThresholds); + + if (DEBUG) { + Slog.e(TAG, "Brightness Thresholds = " + thresholds); + } + + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS, + thresholds); + } + + void setLowAmbientBrightnessThresholds(int[] ambientThresholds) { + String thresholds = toPropertyValue(ambientThresholds); + + if (DEBUG) { + Slog.e(TAG, "Ambient Thresholds = " + thresholds); + } + + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS, + thresholds); + } + + void setRefreshRateInHighZone(int fps) { + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE, + String.valueOf(fps)); + } + + void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) { + String thresholds = toPropertyValue(brightnessThresholds); + + if (DEBUG) { + Slog.e(TAG, "Brightness Thresholds = " + thresholds); + } + + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS, + thresholds); + } + + void setHighAmbientBrightnessThresholds(int[] ambientThresholds) { + String thresholds = toPropertyValue(ambientThresholds); + + if (DEBUG) { + Slog.e(TAG, "Ambient Thresholds = " + thresholds); + } + + putPropertyAndNotify( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS, + thresholds); + } + + @NonNull + private static String toPropertyValue(@NonNull int[] intArray) { + return Arrays.stream(intArray) + .mapToObj(Integer::toString) + .collect(Collectors.joining(",")); + } + } + + private void setBrightness(int brightness) { + Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, + brightness); + mInjector.notifyBrightnessChanged(); + waitForIdleSync(); + } + + private void setPeakRefreshRate(float fps) { + Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, + fps); + mInjector.notifyPeakRefreshRateChanged(); + waitForIdleSync(); + } + + private static SensorManager createMockSensorManager(Sensor... sensors) { + SensorManager sensorManager = Mockito.mock(SensorManager.class); + when(sensorManager.getSensorList(anyInt())).then((invocation) -> { + List<Sensor> requestedSensors = new ArrayList<>(); + int type = invocation.getArgument(0); + for (Sensor sensor : sensors) { + if (sensor.getType() == type || type == Sensor.TYPE_ALL) { + requestedSensors.add(sensor); + } + } + return requestedSensors; + }); + + when(sensorManager.getDefaultSensor(anyInt())).then((invocation) -> { + int type = invocation.getArgument(0); + for (Sensor sensor : sensors) { + if (sensor.getType() == type) { + return sensor; + } + } + return null; + }); + return sensorManager; + } + + private static Sensor createLightSensor() { + try { + return TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + } catch (Exception e) { + // There's nothing we can do if this fails, just throw a RuntimeException so that we + // don't have to mark every function that might call this as throwing Exception + throw new RuntimeException("Failed to create a light sensor", e); + } + } + + private void waitForIdleSync() { + mHandler.runWithScissors(() -> { }, 500 /*timeout*/); + } + + static class FakesInjector implements DisplayModeDirector.Injector { + private final FakeDeviceConfig mDeviceConfig; + private ContentObserver mBrightnessObserver; + private ContentObserver mPeakRefreshRateObserver; + + FakesInjector() { + mDeviceConfig = new FakeDeviceConfig(); + } + + @NonNull + public FakeDeviceConfig getDeviceConfig() { + return mDeviceConfig; + } + + @Override + public void registerBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + if (mBrightnessObserver != null) { + throw new IllegalStateException("Tried to register a second brightness observer"); + } + mBrightnessObserver = observer; + } + + @Override + public void unregisterBrightnessObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + mBrightnessObserver = null; + } + + void notifyBrightnessChanged() { + if (mBrightnessObserver != null) { + mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI); + } + } + + @Override + public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + mPeakRefreshRateObserver = observer; + } + + void notifyPeakRefreshRateChanged() { + if (mPeakRefreshRateObserver != null) { + mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/, + PEAK_REFRESH_RATE_URI); + } + } + + @Override + public boolean isDeviceInteractive(@NonNull Context context) { + return true; + } + } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index ba851992cbad..2c2fdcaab340 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -519,10 +519,24 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertTrue(mService.setLockCredential(password, password, PRIMARY_USER_ID)); + assertNoOrphanedFilesLeft(PRIMARY_USER_ID); + } + + @Test + public void testAddingEscrowToken_NoOrphanedFilesLeft() throws Exception { + final byte[] token = "some-high-entropy-secure-token".getBytes(); + for (int i = 0; i < 16; i++) { + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + mLocalService.removeEscrowToken(handle, PRIMARY_USER_ID); + } + assertNoOrphanedFilesLeft(PRIMARY_USER_ID); + } + private void assertNoOrphanedFilesLeft(int userId) { String handleString = String.format("%016x", - mService.getSyntheticPasswordHandleLocked(PRIMARY_USER_ID)); - File directory = mStorage.getSyntheticPasswordDirectoryForUser(PRIMARY_USER_ID); + mService.getSyntheticPasswordHandleLocked(userId)); + File directory = mStorage.getSyntheticPasswordDirectoryForUser(userId); for (File file : directory.listFiles()) { String[] parts = file.getName().split("\\."); if (!parts[0].equals(handleString) && !parts[0].equals("0000000000000000")) { diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index d244e687c8b8..d7897dbb6133 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -77,6 +77,7 @@ import com.android.server.SystemService; import com.android.server.lights.LightsManager; import com.android.server.policy.WindowManagerPolicy; import com.android.server.power.PowerManagerService.BatteryReceiver; +import com.android.server.power.PowerManagerService.BinderService; import com.android.server.power.PowerManagerService.Injector; import com.android.server.power.PowerManagerService.NativeWrapper; import com.android.server.power.PowerManagerService.UserSwitchedReceiver; @@ -173,6 +174,7 @@ public class PowerManagerServiceTest { when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false); when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true); when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn(""); + when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true); mDisplayPowerRequest = new DisplayPowerRequest(); addLocalServiceMock(LightsManager.class, mLightsManagerMock); @@ -967,4 +969,72 @@ public class PowerManagerServiceTest { assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test2")) .isFalse(); } + + @Test + public void testIsAmbientDisplaySuppressedForTokenByApp_ambientDisplayUnavailable() + throws Exception { + createService(); + when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false); + + BinderService service = mService.getBinderServiceInstance(); + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid())) + .isFalse(); + } + + @Test + public void testIsAmbientDisplaySuppressedForTokenByApp_default() + throws Exception { + createService(); + + BinderService service = mService.getBinderServiceInstance(); + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid())) + .isFalse(); + } + + @Test + public void testIsAmbientDisplaySuppressedForTokenByApp_suppressedByCallingApp() + throws Exception { + createService(); + BinderService service = mService.getBinderServiceInstance(); + service.suppressAmbientDisplay("test", true); + + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid())) + .isTrue(); + // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app. + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123)) + .isFalse(); + } + + @Test + public void testIsAmbientDisplaySuppressedForTokenByApp_notSuppressedByCallingApp() + throws Exception { + createService(); + BinderService service = mService.getBinderServiceInstance(); + service.suppressAmbientDisplay("test", false); + + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid())) + .isFalse(); + // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app. + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123)) + .isFalse(); + } + + @Test + public void testIsAmbientDisplaySuppressedForTokenByApp_multipleTokensSuppressedByCallingApp() + throws Exception { + createService(); + BinderService service = mService.getBinderServiceInstance(); + service.suppressAmbientDisplay("test1", true); + service.suppressAmbientDisplay("test2", true); + + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", Binder.getCallingUid())) + .isTrue(); + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", Binder.getCallingUid())) + .isTrue(); + // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app. + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", /* appUid= */ 123)) + .isFalse(); + assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", /* appUid= */ 123)) + .isFalse(); + } } diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java index 614949c91b9a..1494642edb56 100644 --- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java @@ -79,7 +79,9 @@ public class UriGrantsManagerServiceTest { @Before public void setUp() throws Exception { mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext()); - mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService(); + mService = UriGrantsManagerService + .createForTest(mContext, mContext.getFilesDir()) + .getLocalService(); } /** diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index a07e60ce838e..1ced467dffa1 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -141,10 +141,13 @@ public class AppStandbyControllerTests { private AppStandbyController mController; private CountDownLatch mStateChangedLatch = new CountDownLatch(1); + private String mLatchPkgName = null; private AppIdleStateChangeListener mListener = new AppIdleStateChangeListener() { @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { + // Ignore events not related to mLatchPkgName, if set. + if (mLatchPkgName != null && !mLatchPkgName.equals(packageName)) return; mStateChangedLatch.countDown(); } }; @@ -387,6 +390,7 @@ public class AppStandbyControllerTests { mInjector.mElapsedRealtime, false)); controller.addListener(mListener); + mLatchPkgName = null; return controller; } @@ -1390,7 +1394,7 @@ public class AppStandbyControllerTests { @Test public void testUnexemptedSyncScheduled() throws Exception { - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.addListener(mListener); assertEquals("Test package did not start in the Never bucket", STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); @@ -1402,7 +1406,7 @@ public class AppStandbyControllerTests { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should not elevate a non Never bucket", @@ -1413,7 +1417,7 @@ public class AppStandbyControllerTests { public void testExemptedSyncScheduled() throws Exception { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); mInjector.mDeviceIdleMode = true; - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled in doze should set bucket to working set", @@ -1421,7 +1425,7 @@ public class AppStandbyControllerTests { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); mInjector.mDeviceIdleMode = false; - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled while not in doze should set bucket to active", @@ -1590,10 +1594,19 @@ public class AppStandbyControllerTests { } private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception { - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(pkg); mController.setAppStandbyBucket(pkg, user, bucket, reason); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Failed to set package bucket", bucket, getStandbyBucket(mController, PACKAGE_1)); } + + private void rearmLatch(String pkgName) { + mLatchPkgName = pkgName; + mStateChangedLatch = new CountDownLatch(1); + } + + private void rearmLatch() { + rearmLatch(null); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java index 2904a5b73646..a67f64596ef5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java +++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.wm.utils; +package com.android.server.testutils; import android.annotation.NonNull; import android.provider.DeviceConfig; @@ -22,6 +22,7 @@ import android.util.ArrayMap; import android.util.Pair; import com.android.internal.util.Preconditions; +import com.android.server.utils.DeviceConfigInterface; import java.lang.reflect.Constructor; import java.util.HashMap; @@ -122,6 +123,19 @@ public class FakeDeviceConfigInterface implements DeviceConfigInterface { } @Override + public float getFloat(String namespace, String name, float defaultValue) { + String value = getProperty(namespace, name); + if (value == null) { + return defaultValue; + } + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + @Override public boolean getBoolean(String namespace, String name, boolean defaultValue) { String value = getProperty(namespace, name); return value != null ? Boolean.parseBoolean(value) : defaultValue; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index abcc14c6be93..d088f37b69ba 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -103,6 +103,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 1 << 30); + private InjectableSystemClock mSystemClock = new FakeSystemClock(); private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; @@ -154,7 +155,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { assertTrue(accessibilityManager.isEnabled()); mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger, - mNotificationInstanceIdSequence)); + mSystemClock, mNotificationInstanceIdSequence)); mService.setAudioManager(mAudioManager); mService.setVibrator(mVibrator); mService.setSystemReady(true); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/FakeSystemClock.java b/services/tests/uiservicestests/src/com/android/server/notification/FakeSystemClock.java new file mode 100644 index 000000000000..c960f1766612 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/FakeSystemClock.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 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.notification; + +import java.util.ArrayList; +import java.util.List; + +/** + * A fake {@link InjectableSystemClock} + * + * Attempts to simulate the behavior of a real system clock. Time can be moved forward but not + * backwards. uptimeMillis, elapsedRealtime, and currentThreadTimeMillis are all kept in sync. + * + * Unless otherwise specified, uptimeMillis and elapsedRealtime will advance the same amount with + * every call to {@link #advanceTime(long)}. Thread time always lags by 50% of the uptime + * advancement to simulate time loss due to scheduling. + * + * @hide + */ +public class FakeSystemClock implements InjectableSystemClock { + private long mUptimeMillis = 10000; + private long mElapsedRealtime = 10000; + private long mCurrentThreadTimeMillis = 10000; + + private long mCurrentTimeMillis = 1555555500000L; + + private final List<ClockTickListener> mListeners = new ArrayList<>(); + @Override + public long uptimeMillis() { + return mUptimeMillis; + } + + @Override + public long elapsedRealtime() { + return mElapsedRealtime; + } + + @Override + public long elapsedRealtimeNanos() { + return mElapsedRealtime * 1000000 + 447; + } + + @Override + public long currentThreadTimeMillis() { + return mCurrentThreadTimeMillis; + } + + @Override + public long currentTimeMillis() { + return mCurrentTimeMillis; + } + + public void setUptimeMillis(long uptime) { + advanceTime(uptime - mUptimeMillis); + } + + public void setCurrentTimeMillis(long millis) { + mCurrentTimeMillis = millis; + } + + public void advanceTime(long uptime) { + advanceTime(uptime, 0); + } + + public void advanceTime(long uptime, long sleepTime) { + if (uptime < 0 || sleepTime < 0) { + throw new IllegalArgumentException("Time cannot go backwards."); + } + + if (uptime > 0 || sleepTime > 0) { + mUptimeMillis += uptime; + mElapsedRealtime += uptime + sleepTime; + mCurrentTimeMillis += uptime + sleepTime; + + mCurrentThreadTimeMillis += Math.ceil(uptime * 0.5); + + for (ClockTickListener listener : mListeners) { + listener.onClockTick(); + } + } + } + + public void addListener(ClockTickListener listener) { + mListeners.add(listener); + } + + public void removeListener(ClockTickListener listener) { + mListeners.remove(listener); + } + + public interface ClockTickListener { + void onClockTick(); + } + + private static final long START_TIME = 10000; +} + 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 24384b1d4f31..4259831c15f8 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -199,6 +199,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; @@ -287,18 +288,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { 1 << 30); @Mock StatusBarManagerInternal mStatusBar; + private final FakeSystemClock mSystemClock = new FakeSystemClock(); // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { int countSystemChecks = 0; boolean isSystemUid = true; int countLogSmartSuggestionsVisible = 0; + // If true, don't enqueue the PostNotificationRunnables, just trap them + boolean trapEnqueuedNotifications = false; + final ArrayList<NotificationManagerService.PostNotificationRunnable> trappedRunnables = + new ArrayList<>(); @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; - TestableNotificationManagerService(Context context, NotificationRecordLogger logger, + TestableNotificationManagerService( + Context context, + NotificationRecordLogger logger, + InjectableSystemClock systemClock, InstanceIdSequence notificationInstanceIdSequence) { - super(context, logger, notificationInstanceIdSequence); + super(context, logger, systemClock, notificationInstanceIdSequence); } RankingHelper getRankingHelper() { @@ -353,6 +362,23 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { return new String[] {PKG_O}; } + @Override + protected void postPostNotificationRunnableMaybeDelayedLocked(NotificationRecord record, + PostNotificationRunnable runnable) { + if (trapEnqueuedNotifications) { + trappedRunnables.add(runnable); + return; + } + + super.postPostNotificationRunnableMaybeDelayedLocked(record, runnable); + } + + void drainTrappedRunnableQueue() { + for (Runnable r : trappedRunnables) { + getWorkHandler().post(r); + } + } + private void setNotificationAssistantAccessGrantedCallback( @Nullable NotificationAssistantAccessGrantedCallback callback) { this.mNotificationAssistantAccessGrantedCallback = callback; @@ -402,7 +428,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, - mNotificationInstanceIdSequence); + mSystemClock, mNotificationInstanceIdSequence); // Use this testable looper. mTestableLooper = TestableLooper.get(this); @@ -1344,10 +1370,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); - Thread.sleep(1); // make sure the system clock advances before the next step + mSystemClock.advanceTime(1); // THEN it is canceled mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); - Thread.sleep(1); // here too + mSystemClock.advanceTime(1); // THEN it is posted again (before the cancel has a chance to finish) mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); @@ -1362,6 +1388,60 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testChangeSystemTimeAfterPost_thenCancel_noFgs() throws Exception { + // GIVEN time X + mSystemClock.setCurrentTimeMillis(10000); + + // GIVEN a notification is posted + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), + sbn.getNotification(), sbn.getUserId()); + mSystemClock.advanceTime(1); + waitForIdle(); + + // THEN the system time is changed to an earlier time + mSystemClock.setCurrentTimeMillis(5000); + + // THEN a cancel is requested + mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); + waitForIdle(); + + // It should work + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(PKG); + assertEquals(0, notifs.length); + assertEquals(0, mService.getNotificationRecordCount()); + } + + @Test + public void testChangeSystemTimeAfterPost_thenCancel_fgs() throws Exception { + // GIVEN time X + mSystemClock.setCurrentTimeMillis(10000); + + // GIVEN a notification is posted + final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); + sbn.getNotification().flags = + Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), + sbn.getNotification(), sbn.getUserId()); + mSystemClock.advanceTime(1); + waitForIdle(); + + // THEN the system time is changed to an earlier time + mSystemClock.setCurrentTimeMillis(5000); + + // THEN a cancel is requested + mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); + waitForIdle(); + + // It should work + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(PKG); + assertEquals(0, notifs.length); + assertEquals(0, mService.getNotificationRecordCount()); + } + + @Test public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, PKG, "testCancelNotificationWhilePostedAndEnqueued", 0, @@ -1383,6 +1463,56 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testDelayCancelWhenEnqueuedHasNotPosted() throws Exception { + // Don't allow PostNotificationRunnables to execute so we can set up problematic state + mService.trapEnqueuedNotifications = true; + // GIVEN an enqueued notification + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testDelayCancelWhenEnqueuedHasNotPosted", 0, + generateNotificationRecord(null).getNotification(), 0); + mSystemClock.advanceTime(1); + // WHEN a cancel is requested before it has posted + mBinderService.cancelNotificationWithTag(PKG, PKG, + "testDelayCancelWhenEnqueuedHasNotPosted", 0, 0); + + waitForIdle(); + + // THEN the cancel notification runnable is captured and associated with that record + ArrayMap<NotificationRecord, + ArrayList<NotificationManagerService.CancelNotificationRunnable>> delayed = + mService.mDelayedCancelations; + Set<NotificationRecord> keySet = delayed.keySet(); + assertEquals(1, keySet.size()); + } + + @Test + public void testDelayedCancelsExecuteAfterPost() throws Exception { + // Don't allow PostNotificationRunnables to execute so we can set up problematic state + mService.trapEnqueuedNotifications = true; + // GIVEN an enqueued notification + mBinderService.enqueueNotificationWithTag(PKG, PKG, + "testDelayCancelWhenEnqueuedHasNotPosted", 0, + generateNotificationRecord(null).getNotification(), 0); + mSystemClock.advanceTime(1); + // WHEN a cancel is requested before it has posted + mBinderService.cancelNotificationWithTag(PKG, PKG, + "testDelayCancelWhenEnqueuedHasNotPosted", 0, 0); + + waitForIdle(); + + // We're now in a state with an a notification awaiting PostNotificationRunnable to execute + // WHEN the PostNotificationRunnable is allowed to execute + mService.drainTrappedRunnableQueue(); + waitForIdle(); + + // THEN the cancel executes and the notification is removed + StatusBarNotification[] notifs = + mBinderService.getActiveNotifications(PKG); + assertEquals(0, notifs.length); + assertEquals(0, mService.getNotificationRecordCount()); + } + + @Test public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception { NotificationRecord r = generateNotificationRecord(null); final StatusBarNotification sbn = r.getSbn(); @@ -2529,8 +2659,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testHasCompanionDevice_noService() { - mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, - mNotificationInstanceIdSequence); + mService = + new TestableNotificationManagerService(mContext, mNotificationRecordLogger, + mSystemClock, mNotificationInstanceIdSequence); assertFalse(mService.hasCompanionDevice(mListener)); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index a118e0df1338..3b1059761357 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -96,6 +96,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.TestableContentResolver; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IntArray; import android.util.Pair; import android.util.StatsEvent; import android.util.Xml; @@ -3284,7 +3285,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setImportantConversation(true); mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); - List<ConversationChannelWrapper> convos = mHelper.getConversations(false); + List<ConversationChannelWrapper> convos = + mHelper.getConversations(IntArray.wrap(new int[] {0}), false); assertEquals(3, convos.size()); assertTrue(conversationWrapperContainsChannel(convos, channel)); @@ -3293,6 +3295,44 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void testGetConversations_multiUser() { + String convoId = "convo"; + NotificationChannel messages = + new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + + NotificationChannel messagesUser10 = + new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel( + PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false); + + NotificationChannel messagesFromB = + new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); + messagesFromB.setConversationId(messages.getId(), "different convo"); + mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false); + + NotificationChannel messagesFromBUser10 = + new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); + messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo"); + mHelper.createNotificationChannel( + PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false); + + + List<ConversationChannelWrapper> convos = + mHelper.getConversations(IntArray.wrap(new int[] {0}), false); + + assertEquals(1, convos.size()); + assertTrue(conversationWrapperContainsChannel(convos, messagesFromB)); + + convos = + mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false); + + assertEquals(2, convos.size()); + assertTrue(conversationWrapperContainsChannel(convos, messagesFromB)); + assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10)); + } + + @Test public void testGetConversations_notDemoted() { String convoId = "convo"; NotificationChannel messages = @@ -3322,7 +3362,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setImportantConversation(true); mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); - List<ConversationChannelWrapper> convos = mHelper.getConversations(false); + List<ConversationChannelWrapper> convos = + mHelper.getConversations(IntArray.wrap(new int[] {0}), false); assertEquals(2, convos.size()); assertTrue(conversationWrapperContainsChannel(convos, channel)); @@ -3360,7 +3401,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setConversationId(calls.getId(), convoId); mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); - List<ConversationChannelWrapper> convos = mHelper.getConversations(true); + List<ConversationChannelWrapper> convos = + mHelper.getConversations(IntArray.wrap(new int[] {0}), true); assertEquals(2, convos.size()); assertTrue(conversationWrapperContainsChannel(convos, channel)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 3281c3f4cfb9..ac2c6193c677 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -103,12 +103,14 @@ public class RoleObserverTest extends UiServiceTestCase { private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 1 << 30); private List<UserInfo> mUsers; + private InjectableSystemClock mSystemClock = new FakeSystemClock(); private static class TestableNotificationManagerService extends NotificationManagerService { TestableNotificationManagerService(Context context, NotificationRecordLogger logger, + InjectableSystemClock systemClock, InstanceIdSequence notificationInstanceIdSequence) { - super(context, logger, notificationInstanceIdSequence); + super(context, logger, systemClock, notificationInstanceIdSequence); } @Override @@ -136,7 +138,7 @@ public class RoleObserverTest extends UiServiceTestCase { when(mUm.getUsers()).thenReturn(mUsers); mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, - mNotificationInstanceIdSequence); + mSystemClock, mNotificationInstanceIdSequence); mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor); try { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index e1ce431fc97c..5b516a9de350 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -32,6 +32,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.timeout; +import android.app.WaitResult; import android.content.Intent; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; @@ -163,10 +164,15 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { @Test public void testOnActivityLaunchFinished() { + // Assume that the process is started (ActivityBuilder has mocked the returned value of + // ATMS#getProcessController) but the activity has not attached process. + mTopActivity.app = null; onActivityLaunched(mTopActivity); notifyTransitionStarting(mTopActivity); - notifyWindowsDrawn(mTopActivity); + final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity); + assertWithMessage("Warm launch").that(info.getLaunchState()) + .isEqualTo(WaitResult.LAUNCH_STATE_WARM); verifyOnActivityLaunchFinished(mTopActivity); verifyNoMoreInteractions(mLaunchObserver); @@ -201,7 +207,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { notifyActivityLaunching(noDrawnActivity.intent); notifyActivityLaunched(START_SUCCESS, noDrawnActivity); - noDrawnActivity.destroyIfPossible("test"); + noDrawnActivity.mVisibleRequested = false; mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity)); @@ -216,7 +222,9 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false); notifyTransitionStarting(mTopActivity); // The pending fully drawn event should send when the actual windows drawn event occurs. - notifyWindowsDrawn(mTopActivity); + final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity); + assertWithMessage("Hot launch").that(info.getLaunchState()) + .isEqualTo(WaitResult.LAUNCH_STATE_HOT); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong()); verifyOnActivityLaunchFinished(mTopActivity); @@ -260,8 +268,8 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyTransitionStarting(reasons); } - private void notifyWindowsDrawn(ActivityRecord r) { - mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos()); + private ActivityMetricsLogger.TransitionInfoSnapshot notifyWindowsDrawn(ActivityRecord r) { + return mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index 880c486c15af..d42ab72a22b7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -20,6 +20,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; import static com.android.server.wm.DisplayArea.Type.ANY; import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS; @@ -29,11 +32,15 @@ import static com.android.server.wm.DisplayArea.Type.typeOf; import static com.android.server.wm.testing.Assert.assertThrows; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import android.content.pm.ActivityInfo; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; +import android.view.View; +import android.view.WindowManager; import org.junit.Rule; import org.junit.Test; @@ -97,6 +104,42 @@ public class DisplayAreaTest { assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ANY)); } + + @Test + public void testGetOrientation() { + final DisplayArea.Tokens area = new DisplayArea.Tokens(mWmsRule.getWindowManagerService(), + ABOVE_TASKS, "test"); + final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY); + spyOn(token); + doReturn(mock(DisplayContent.class)).when(token).getDisplayContent(); + doNothing().when(token).setParent(any()); + final WindowState win = createWindowState(token); + spyOn(win); + doNothing().when(win).setParent(any()); + win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + token.addChild(win, 0); + area.addChild(token); + + doReturn(true).when(win).isVisible(); + + assertEquals("Visible window can request orientation", + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, + area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); + + doReturn(false).when(win).isVisible(); + + assertEquals("Invisible window cannot request orientation", + ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, + area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); + } + + private WindowState createWindowState(WindowToken token) { + return new WindowState(mWmsRule.getWindowManagerService(), mock(Session.class), + new TestIWindow(), token, null /* parentWindow */, 0 /* appOp */, 0 /* seq*/, + new WindowManager.LayoutParams(), View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */, + false /* ownerCanAddInternalSystemWindow */, null); + } + private WindowToken createWindowToken(int type) { return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(), type, false /* persist */, null /* displayContent */, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 1948003a7499..d99606b704e4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -32,6 +32,7 @@ import static android.view.Display.FLAG_PRIVATE; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; +import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_90; import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; @@ -102,6 +103,7 @@ import android.view.IDisplayWindowRotationCallback; import android.view.IDisplayWindowRotationController; import android.view.ISystemGestureExclusionListener; import android.view.IWindowManager; +import android.view.InsetsState; import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceControl.Transaction; @@ -1114,6 +1116,17 @@ public class DisplayContentTests extends WindowTestsBase { assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM)); + // If the visibility of insets state is changed, the rotated state should be updated too. + final InsetsState rotatedState = app.getFixedRotationTransformInsetsState(); + final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState(); + assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(), + rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + state.getSource(ITYPE_STATUS_BAR).setVisible( + !rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + mDisplayContent.getInsetsStateController().notifyInsetsChanged(); + assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(), + rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + final Rect outFrame = new Rect(); final Rect outInsets = new Rect(); final Rect outStableInsets = new Rect(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 58d4104bf2b0..7e3613411b37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -52,10 +52,13 @@ import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.testng.Assert.expectThrows; @@ -927,6 +930,25 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + public void testFixedRotationInsetsSourceFrame() { + final DisplayInfo info = mDisplayContent.getDisplayInfo(); + info.rotation = mFrames.mRotation; + mDisplayContent.mBaseDisplayHeight = info.logicalHeight = mFrames.mDisplayHeight; + mDisplayContent.mBaseDisplayWidth = info.logicalWidth = mFrames.mDisplayWidth; + mDisplayContent.getInsetsStateController().onPostLayout(); + mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode); + doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent) + .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord)); + final Rect frame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + doReturn(mDisplayPolicy).when(mDisplayContent).getDisplayPolicy(); + mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord); + final Rect rotatedFrame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + + assertEquals(DISPLAY_WIDTH, frame.width()); + assertEquals(DISPLAY_HEIGHT, rotatedFrame.width()); + } + + @Test public void testScreenDecorWindows() { final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow"); mWindow.mAttrs.flags = FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java index f53894ad9ec5..112b2e98a7f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java @@ -31,7 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.internal.util.Preconditions; -import com.android.server.wm.utils.FakeDeviceConfigInterface; +import com.android.server.testutils.FakeDeviceConfigInterface; import org.junit.After; import org.junit.Test; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 90af8a1b3199..7d84920187a0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -38,10 +38,13 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import android.app.StatusBarManager; import android.platform.test.annotations.Presubmit; import android.view.InsetsSourceControl; import android.view.InsetsState; @@ -49,6 +52,8 @@ import android.view.test.InsetsModeSession; import androidx.test.filters.SmallTest; +import com.android.server.statusbar.StatusBarManagerInternal; + import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -222,6 +227,23 @@ public class InsetsPolicyTest extends WindowTestsBase { assertNotNull(fullscreenAppControls); assertEquals(1, fullscreenAppControls.length); assertEquals(ITYPE_STATUS_BAR, fullscreenAppControls[0].getType()); + + // Assume mFocusedWindow is updated but mTopFullscreenOpaqueWindowState hasn't. + final WindowState newFocusedFullscreenApp = addWindow(TYPE_APPLICATION, "newFullscreenApp"); + final InsetsState newRequestedState = new InsetsState(); + newRequestedState.getSource(ITYPE_STATUS_BAR).setVisible(true); + newFocusedFullscreenApp.updateRequestedInsetsState(newRequestedState); + // Make sure status bar is hidden by previous insets state. + mDisplayContent.getInsetsPolicy().updateBarControlTarget(fullscreenApp); + + final StatusBarManagerInternal sbmi = + mDisplayContent.getDisplayPolicy().getStatusBarManagerInternal(); + clearInvocations(sbmi); + mDisplayContent.getInsetsPolicy().updateBarControlTarget(newFocusedFullscreenApp); + // The status bar should be shown by newFocusedFullscreenApp even + // mTopFullscreenOpaqueWindowState is still fullscreenApp. + verify(sbmi).setWindowState(mDisplayContent.mDisplayId, StatusBarManager.WINDOW_STATUS_BAR, + StatusBarManager.WINDOW_STATE_SHOWING); } @Test @@ -309,6 +331,15 @@ public class InsetsPolicyTest extends WindowTestsBase { final InsetsState state = policy.getInsetsForDispatch(mAppWindow); state.setSourceVisible(ITYPE_STATUS_BAR, true); state.setSourceVisible(ITYPE_NAVIGATION_BAR, true); + + final InsetsState clientState = mAppWindow.getInsetsState(); + // The transient bar states for client should be invisible. + assertFalse(clientState.getSource(ITYPE_STATUS_BAR).isVisible()); + assertFalse(clientState.getSource(ITYPE_NAVIGATION_BAR).isVisible()); + // The original state shouldn't be modified. + assertTrue(state.getSource(ITYPE_STATUS_BAR).isVisible()); + assertTrue(state.getSource(ITYPE_NAVIGATION_BAR).isVisible()); + policy.onInsetsModified(mAppWindow, state); waitUntilWindowAnimatorIdle(); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 73ac408f7980..3db00189e525 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -30,6 +30,9 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -329,6 +332,26 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @Test + public void testTransientVisibilityOfFixedRotationState() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final InsetsSourceProvider provider = getController().getSourceProvider(ITYPE_STATUS_BAR); + provider.setWindow(statusBar, null, null); + + final InsetsState rotatedState = new InsetsState(app.getInsetsState(), + true /* copySources */); + spyOn(app.mToken); + doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState(); + assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + + provider.getSource().setVisible(false); + mDisplayContent.getInsetsPolicy().showTransient(new int[] { ITYPE_STATUS_BAR }); + + assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR)); + assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible()); + } + private InsetsStateController getController() { return mDisplayContent.getInsetsStateController(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index f2771175b523..730e9beecf77 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -395,6 +395,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // The rotation transform should be cleared after updating orientation with display. assertFalse(activity.hasFixedRotationTransform()); assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); + + // Simulate swiping up recents (home) in different rotation. + final ActivityRecord home = mDefaultDisplay.getDefaultTaskDisplayArea().getHomeActivity(); + mDefaultDisplay.setFixedRotationLaunchingApp(home, (mDefaultDisplay.getRotation() + 1) % 4); + mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks, + mDefaultDisplay.getDisplayId()); + initializeRecentsAnimationController(mController, home); + assertTrue(home.hasFixedRotationTransform()); + + // Assume recents activity becomes invisible for some reason (e.g. screen off). + home.setVisible(false); + mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + // Although there won't be a transition finish callback, the fixed rotation must be cleared. + assertFalse(home.hasFixedRotationTransform()); + assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index a979c862a8e4..250dc2469be1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -568,6 +568,8 @@ public class SizeCompatTests extends ActivityTestsBase { private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; + params.setFitInsetsSides(0); + params.setFitInsetsTypes(0); final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( activity.mWmService, mock(Session.class), new TestIWindow(), params, activity); WindowTestsBase.makeWindowVisible(w); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java index 52100116df53..7a0ef0d7d7a9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java @@ -32,7 +32,7 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import com.android.server.wm.utils.FakeDeviceConfigInterface; +import com.android.server.testutils.FakeDeviceConfigInterface; import org.junit.After; import org.junit.Before; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index da2d4d82481b..afe186cba0db 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -373,6 +373,14 @@ public class TelecomManager { "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; /** + * A string value for {@link #EXTRA_CALL_DISCONNECT_MESSAGE}, indicates the call was dropped by + * lower layers + * @hide + */ + public static final String CALL_AUTO_DISCONNECT_MESSAGE_STRING = + "Call dropped by lower layers"; + + /** * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED} * containing the component name of the associated connection service. * @hide diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index 02597d548361..e67354982b05 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -96,6 +96,19 @@ public class StagedInstallInternalTest { assertSessionReady(sessionId); } + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception { + InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK", + Install.single(TestApp.AIncompleteSplit).setStaged()); + } + + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage() + throws Exception { + InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK", + Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged()); + } + private static void assertSessionReady(int sessionId) { assertSessionState(sessionId, (session) -> assertThat(session.isStagedSessionReady()).isTrue()); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index b7c9e59bd3ac..8cfe187d387c 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -27,6 +27,7 @@ import android.cts.install.lib.host.InstallUtilsHost; import com.android.ddmlib.Log; import com.android.tests.rollback.host.AbandonSessionsRule; +import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import com.android.tradefed.util.ProcessInfo; @@ -38,6 +39,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; @RunWith(DeviceJUnit4ClassRunner.class) public class StagedInstallInternalTest extends BaseHostJUnit4Test { @@ -180,9 +184,55 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { assertThat(sessionIds.length).isEqualTo(3); } + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception { + List<String> before = getStagingDirectories(); + runPhase("testStagedInstallationShouldCleanUpOnValidationFailure"); + List<String> after = getStagingDirectories(); + assertThat(after).isEqualTo(before); + } + + @Test + public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage() + throws Exception { + List<String> before = getStagingDirectories(); + runPhase("testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage"); + List<String> after = getStagingDirectories(); + assertThat(after).isEqualTo(before); + } + + @Test + public void testOrphanedStagingDirectoryGetsCleanedUpOnReboot() throws Exception { + //create random directories in /data/app-staging folder + getDevice().enableAdbRoot(); + getDevice().executeShellCommand("mkdir /data/app-staging/session_123"); + getDevice().executeShellCommand("mkdir /data/app-staging/random_name"); + getDevice().disableAdbRoot(); + + assertThat(getStagingDirectories()).isNotEmpty(); + getDevice().reboot(); + assertThat(getStagingDirectories()).isEmpty(); + } + + private List<String> getStagingDirectories() throws DeviceNotAvailableException { + String baseDir = "/data/app-staging"; + try { + getDevice().enableAdbRoot(); + return getDevice().getFileEntry(baseDir).getChildren(false) + .stream().filter(entry -> entry.getName().matches("session_\\d+")) + .map(entry -> entry.getName()) + .collect(Collectors.toList()); + } catch (Exception e) { + // Return an empty list if any error + return Collections.EMPTY_LIST; + } finally { + getDevice().disableAdbRoot(); + } + } + private void restartSystemServer() throws Exception { // Restart the system server - final long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); + long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); getDevice().enableAdbRoot(); // Need root to restart system server assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system"); diff --git a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java index e482708e385b..a0a5a293f2e4 100644 --- a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java @@ -92,6 +92,14 @@ public class FakeSettingsProvider extends MockContentProvider { } /** + * Creates a {@link org.junit.rules.TestRule} that makes sure {@link #clearSettingsProvider()} + * is triggered before and after each test. + */ + public static FakeSettingsProviderRule rule() { + return new FakeSettingsProviderRule(); + } + + /** * This needs to be called before and after using the FakeSettingsProvider class. */ public static void clearSettingsProvider() { diff --git a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java new file mode 100644 index 000000000000..c4e9545dfde2 --- /dev/null +++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.test; + +import android.content.Context; +import android.provider.Settings; +import android.test.mock.MockContentResolver; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * JUnit Rule helps keeping test {@link FakeSettingsProvider} clean. + * + * <p>It clears {@link FakeSettingsProvider} before and after each test. Example use: + * <pre class="code"><code class="java"> + * public class ExampleTest { + * + * @Rule public FakeSettingsProviderRule rule = FakeSettingsProvider.rule(); + * + * @Test + * public void shouldDoSomething() { + * ContextResolver cr = rule.mockContentResolver(mContext); + * Settings.Global.putInt(cr, "my_setting_name", 1); + * // Test code relying on my_setting_name value using cr + * } + * } + * </code></pre> + * + * @see FakeSettingsProvider + */ +public final class FakeSettingsProviderRule implements TestRule { + + /** Prevent initialization outside {@link FakeSettingsProvider}. */ + FakeSettingsProviderRule() { + } + + /** + * Creates a {@link MockContentResolver} that uses the {@link FakeSettingsProvider} as the + * {@link Settings#AUTHORITY} provider. + */ + public MockContentResolver mockContentResolver(Context context) { + MockContentResolver contentResolver = new MockContentResolver(context); + contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + return contentResolver; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + public void evaluate() throws Throwable { + FakeSettingsProvider.clearSettingsProvider(); + try { + base.evaluate(); + } finally { + FakeSettingsProvider.clearSettingsProvider(); + } + } + }; + } +} |